Merge branch 'master' into HEAD

Conflicts:
	interface/src/avatar/SkeletonModel.cpp
This commit is contained in:
Brad Davis 2015-10-29 10:24:38 -07:00
commit ccbae81dad
26 changed files with 245 additions and 183 deletions

View file

@ -226,7 +226,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
// if the allowed editors list is empty then everyone can adjust locks // if the allowed editors list is empty then everyone can adjust locks
bool canAdjustLocks = allowedEditors.empty(); bool canAdjustLocks = allowedEditors.empty();
if (allowedEditors.contains(username)) { if (allowedEditors.contains(username, Qt::CaseInsensitive)) {
// we have a non-empty allowed editors list - check if this user is verified to be in it // we have a non-empty allowed editors list - check if this user is verified to be in it
if (!verifiedUsername) { if (!verifiedUsername) {
if (!verifyUserSignature(username, usernameSignature, HifiSockAddr())) { if (!verifyUserSignature(username, usernameSignature, HifiSockAddr())) {

View file

@ -74,8 +74,8 @@ var MSEC_PER_SEC = 1000.0;
// these control how long an abandoned pointer line will hang around // these control how long an abandoned pointer line will hang around
var LIFETIME = 10; var LIFETIME = 10;
var ACTION_LIFETIME = 15; // seconds var ACTION_TTL = 15; // seconds
var ACTION_LIFETIME_REFRESH = 5; var ACTION_TTL_REFRESH = 5;
var PICKS_PER_SECOND_PER_HAND = 5; var PICKS_PER_SECOND_PER_HAND = 5;
var MSECS_PER_SEC = 1000.0; var MSECS_PER_SEC = 1000.0;
@ -429,12 +429,12 @@ function MyController(hand, triggerAction) {
targetRotation: this.currentObjectRotation, targetRotation: this.currentObjectRotation,
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
tag: getTag(), tag: getTag(),
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}); });
if (this.actionID === NULL_ACTION_ID) { if (this.actionID === NULL_ACTION_ID) {
this.actionID = null; this.actionID = null;
} }
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
if (this.actionID !== null) { if (this.actionID !== null) {
this.setState(STATE_CONTINUE_DISTANCE_HOLDING); this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
@ -532,9 +532,9 @@ function MyController(hand, triggerAction) {
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: this.currentObjectRotation, targetRotation: this.currentObjectRotation,
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}); });
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
}; };
this.nearGrabbing = function() { this.nearGrabbing = function() {
@ -587,12 +587,12 @@ function MyController(hand, triggerAction) {
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: this.offsetPosition, relativePosition: this.offsetPosition,
relativeRotation: this.offsetRotation, relativeRotation: this.offsetRotation,
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}); });
if (this.actionID === NULL_ACTION_ID) { if (this.actionID === NULL_ACTION_ID) {
this.actionID = null; this.actionID = null;
} else { } else {
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
this.setState(STATE_CONTINUE_NEAR_GRABBING); this.setState(STATE_CONTINUE_NEAR_GRABBING);
if (this.hand === RIGHT_HAND) { if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
@ -632,16 +632,16 @@ function MyController(hand, triggerAction) {
this.currentObjectTime = now; this.currentObjectTime = now;
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
if (this.actionTimeout - now < ACTION_LIFETIME_REFRESH * MSEC_PER_SEC) { if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) {
// if less than a 5 seconds left, refresh the actions lifetime // if less than a 5 seconds left, refresh the actions ttl
Entities.updateAction(this.grabbedEntity, this.actionID, { Entities.updateAction(this.grabbedEntity, this.actionID, {
hand: this.hand === RIGHT_HAND ? "right" : "left", hand: this.hand === RIGHT_HAND ? "right" : "left",
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
relativePosition: this.offsetPosition, relativePosition: this.offsetPosition,
relativeRotation: this.offsetRotation, relativeRotation: this.offsetRotation,
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}); });
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
} }
}; };

View file

@ -47,7 +47,7 @@ var IDENTITY_QUAT = {
z: 0, z: 0,
w: 0 w: 0
}; };
var ACTION_LIFETIME = 10; // seconds var ACTION_TTL = 10; // seconds
function getTag() { function getTag() {
return "grab-" + MyAvatar.sessionUUID; return "grab-" + MyAvatar.sessionUUID;
@ -403,7 +403,7 @@ Grabber.prototype.moveEvent = function(event) {
var actionArgs = { var actionArgs = {
tag: getTag(), tag: getTag(),
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}; };
if (this.mode === "rotate") { if (this.mode === "rotate") {
@ -424,7 +424,7 @@ Grabber.prototype.moveEvent = function(event) {
targetRotation: this.lastRotation, targetRotation: this.lastRotation,
angularTimeScale: 0.1, angularTimeScale: 0.1,
tag: getTag(), tag: getTag(),
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}; };
} else { } else {
@ -459,7 +459,7 @@ Grabber.prototype.moveEvent = function(event) {
targetPosition: this.targetPosition, targetPosition: this.targetPosition,
linearTimeScale: 0.1, linearTimeScale: 0.1,
tag: getTag(), tag: getTag(),
lifetime: ACTION_LIFETIME ttl: ACTION_TTL
}; };

View file

@ -66,7 +66,8 @@ EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEnt
if (action) { if (action) {
action->deserialize(data); action->deserialize(data);
if (action->lifetimeIsOver()) { if (action->lifetimeIsOver()) {
qDebug() << "InterfaceActionFactory::factoryBA lifetimeIsOver during action creation"; qDebug() << "InterfaceActionFactory::factoryBA lifetimeIsOver during action creation --"
<< action->getExpires() << "<" << usecTimestampNow();
return nullptr; return nullptr;
} }
} }

View file

@ -454,7 +454,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
*/ */
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
if (renderBounding && shouldRenderHead(renderArgs)) { if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) {
_skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f);
} }

View file

@ -243,7 +243,7 @@ QByteArray AvatarActionHold::serialize() const {
dataStream << _linearTimeScale; dataStream << _linearTimeScale;
dataStream << _hand; dataStream << _hand;
dataStream << _expires + getEntityServerClockSkew(); dataStream << localTimeToServerTime(_expires);
dataStream << _tag; dataStream << _tag;
dataStream << _kinematic; dataStream << _kinematic;
dataStream << _kinematicSetVelocity; dataStream << _kinematicSetVelocity;
@ -277,8 +277,10 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
_angularTimeScale = _linearTimeScale; _angularTimeScale = _linearTimeScale;
dataStream >> _hand; dataStream >> _hand;
dataStream >> _expires; quint64 serverExpires;
_expires -= getEntityServerClockSkew(); dataStream >> serverExpires;
_expires = serverTimeToLocalTime(serverExpires);
dataStream >> _tag; dataStream >> _tag;
dataStream >> _kinematic; dataStream >> _kinematic;
dataStream >> _kinematicSetVelocity; dataStream >> _kinematicSetVelocity;

View file

@ -77,7 +77,10 @@ AvatarManager::AvatarManager(QObject* parent) :
void AvatarManager::init() { void AvatarManager::init() {
_myAvatar->init(); _myAvatar->init();
{
QWriteLocker locker(&_hashLock);
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar); _avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
}
connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged, this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection); connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged, this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection);
@ -127,6 +130,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
} else if (avatar->shouldDie()) { } else if (avatar->shouldDie()) {
removeAvatarMotionState(avatar); removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value()); _avatarFades.push_back(avatarIterator.value());
QWriteLocker locker(&_hashLock);
avatarIterator = _avatarHash.erase(avatarIterator); avatarIterator = _avatarHash.erase(avatarIterator);
} else { } else {
avatar->startUpdate(); avatar->startUpdate();
@ -202,6 +206,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) {
if (avatar != _myAvatar && avatar->isInitialized()) { if (avatar != _myAvatar && avatar->isInitialized()) {
removeAvatarMotionState(avatar); removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value()); _avatarFades.push_back(avatarIterator.value());
QWriteLocker locker(&_hashLock);
_avatarHash.erase(avatarIterator); _avatarHash.erase(avatarIterator);
} }
} }
@ -218,6 +223,7 @@ void AvatarManager::clearOtherAvatars() {
} else { } else {
removeAvatarMotionState(avatar); removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value()); _avatarFades.push_back(avatarIterator.value());
QWriteLocker locker(&_hashLock);
avatarIterator = _avatarHash.erase(avatarIterator); avatarIterator = _avatarHash.erase(avatarIterator);
} }
} }
@ -349,5 +355,6 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID)
if (sessionID == _myAvatar->getSessionUUID()) { if (sessionID == _myAvatar->getSessionUUID()) {
return std::static_pointer_cast<Avatar>(_myAvatar); return std::static_pointer_cast<Avatar>(_myAvatar);
} }
return getAvatarHash()[sessionID]; QReadLocker locker(&_hashLock);
return _avatarHash[sessionID];
} }

View file

@ -209,6 +209,11 @@ void MyAvatar::update(float deltaTime) {
setPosition(_goToPosition); setPosition(_goToPosition);
setOrientation(_goToOrientation); setOrientation(_goToOrientation);
_goToPending = false; _goToPending = false;
// updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes
// that happen between render and Application::update (which calls updateSensorToWorldMatrix to do so).
// However, render/MyAvatar::update/Application::update don't always match (e.g., when using the separate avatar update thread),
// so we update now. It's ok if it updates again in the normal way.
updateSensorToWorldMatrix();
} }
if (_referential) { if (_referential) {
@ -1088,7 +1093,11 @@ void MyAvatar::updateLookAtTargetAvatar() {
const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f; const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f;
const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; const float GREATEST_LOOKING_AT_DISTANCE = 10.0f;
foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) { AvatarHash hash;
DependencyManager::get<AvatarManager>()->withAvatarHash([&] (const AvatarHash& locked) {
hash = locked; // make a shallow copy and operate on that, to minimize lock time
});
foreach (const AvatarSharedPointer& avatarPointer, hash) {
auto avatar = static_pointer_cast<Avatar>(avatarPointer); auto avatar = static_pointer_cast<Avatar>(avatarPointer);
bool isCurrentTarget = avatar->getIsLookAtTarget(); bool isCurrentTarget = avatar->getIsLookAtTarget();
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition); float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
@ -1120,7 +1129,6 @@ void MyAvatar::updateLookAtTargetAvatar() {
glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal); glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal);
glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal); glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal);
// First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point. // First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point.
// (We will be adding that offset to the camera position, after making some other adjustments.) // (We will be adding that offset to the camera position, after making some other adjustments.)
glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition(); glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition();

View file

@ -103,15 +103,12 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
if (_owningAvatar->isMyAvatar()) { if (_owningAvatar->isMyAvatar()) {
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
} }
Model::updateRig(deltaTime, parentTransform);
Head* head = _owningAvatar->getHead(); Head* head = _owningAvatar->getHead();
if (_owningAvatar->isMyAvatar()) { if (_owningAvatar->isMyAvatar()) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
Rig::HeadParameters headParams; Rig::HeadParameters headParams;
headParams.modelRotation = getRotation();
headParams.modelTranslation = getTranslation();
headParams.enableLean = qApp->getAvatarUpdater()->isHMDMode(); headParams.enableLean = qApp->getAvatarUpdater()->isHMDMode();
headParams.leanSideways = head->getFinalLeanSideways(); headParams.leanSideways = head->getFinalLeanSideways();
headParams.leanForward = head->getFinalLeanForward(); headParams.leanForward = head->getFinalLeanForward();
@ -145,13 +142,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
} }
headParams.eyeLookAt = head->getLookAtPosition();
headParams.eyeSaccade = head->getSaccade();
headParams.leanJointIndex = geometry.leanJointIndex; headParams.leanJointIndex = geometry.leanJointIndex;
headParams.neckJointIndex = geometry.neckJointIndex; headParams.neckJointIndex = geometry.neckJointIndex;
headParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
headParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f; headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f;
_rig->updateFromHeadParameters(headParams, deltaTime); _rig->updateFromHeadParameters(headParams, deltaTime);
@ -180,7 +172,28 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->updateFromHandParameters(handParams, deltaTime); _rig->updateFromHandParameters(handParams, deltaTime);
// evaluate AnimGraph animation and update jointStates.
Model::updateRig(deltaTime, parentTransform);
Rig::EyeParameters eyeParams;
eyeParams.worldHeadOrientation = headParams.worldHeadOrientation;
eyeParams.eyeLookAt = head->getLookAtPosition();
eyeParams.eyeSaccade = head->getSaccade();
eyeParams.modelRotation = getRotation();
eyeParams.modelTranslation = getTranslation();
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
_rig->updateFromEyeParameters(eyeParams);
// rebuild the jointState transform for the eyes only
_rig->updateJointState(eyeParams.leftEyeJointIndex, parentTransform);
_rig->updateJointState(eyeParams.rightEyeJointIndex, parentTransform);
} else { } else {
Model::updateRig(deltaTime, parentTransform);
// This is a little more work than we really want. // This is a little more work than we really want.
// //
// Other avatars joint, including their eyes, should already be set just like any other joints // Other avatars joint, including their eyes, should already be set just like any other joints
@ -197,9 +210,16 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
head->setBasePitch(glm::degrees(-eulers.x)); head->setBasePitch(glm::degrees(-eulers.x));
head->setBaseYaw(glm::degrees(eulers.y)); head->setBaseYaw(glm::degrees(eulers.y));
head->setBaseRoll(glm::degrees(-eulers.z)); head->setBaseRoll(glm::degrees(-eulers.z));
_rig->updateEyeJoints(geometry.leftEyeJointIndex, geometry.rightEyeJointIndex,
getTranslation(), getRotation(), Rig::EyeParameters eyeParams;
head->getFinalOrientationInWorldFrame(), head->getCorrectedLookAtPosition()); eyeParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
eyeParams.eyeLookAt = head->getCorrectedLookAtPosition();
eyeParams.eyeSaccade = glm::vec3();
eyeParams.modelRotation = getRotation();
eyeParams.modelTranslation = getTranslation();
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
_rig->updateFromEyeParameters(eyeParams);
} }
} }

View file

@ -65,11 +65,12 @@ AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
// Get statistics from the Audio Client // Get statistics from the Audio Client
_stats = &DependencyManager::get<AudioClient>()->getStats(); _stats = &DependencyManager::get<AudioClient>()->getStats();
// Create layouter // Create layout
_form = new QFormLayout(); _form = new QFormLayout();
_form->setSizeConstraint(QLayout::SetFixedSize);
QDialog::setLayout(_form); QDialog::setLayout(_form);
// Load and initilize all channels // Load and initialize all channels
renderStats(); renderStats();
_audioDisplayChannels = QVector<QVector<AudioStatsDisplay*>>(1); _audioDisplayChannels = QVector<QVector<AudioStatsDisplay*>>(1);
@ -80,10 +81,8 @@ AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
_downstreamID = addChannel(_form, _downstreamStats, COLOR3); _downstreamID = addChannel(_form, _downstreamStats, COLOR3);
_upstreamInjectedID = addChannel(_form, _upstreamInjectedStats, COLOR0); _upstreamInjectedID = addChannel(_form, _upstreamInjectedStats, COLOR0);
connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout())); connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout()));
averageUpdateTimer->start(1000); averageUpdateTimer->start(1000);
} }
int AudioStatsDialog::addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color) { int AudioStatsDialog::addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color) {
@ -243,7 +242,6 @@ void AudioStatsDialog::paintEvent(QPaintEvent* event) {
} }
QDialog::paintEvent(event); QDialog::paintEvent(event);
setFixedSize(width(), height());
} }
void AudioStatsDialog::reject() { void AudioStatsDialog::reject() {

View file

@ -72,8 +72,9 @@ BandwidthDialog::BandwidthDialog(QWidget* parent) :
this->setWindowTitle("Bandwidth Details"); this->setWindowTitle("Bandwidth Details");
// Create layouter // Create layout
QFormLayout* form = new QFormLayout(); QFormLayout* form = new QFormLayout();
form->setSizeConstraint(QLayout::SetFixedSize);
this->QDialog::setLayout(form); this->QDialog::setLayout(form);
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>(); QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
@ -118,7 +119,6 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) {
for (unsigned int i=0; i<_CHANNELCOUNT; i++) for (unsigned int i=0; i<_CHANNELCOUNT; i++)
_allChannelDisplays[i]->paint(); _allChannelDisplays[i]->paint();
this->QDialog::paintEvent(event); this->QDialog::paintEvent(event);
this->setFixedSize(this->width(), this->height());
} }
void BandwidthDialog::reject() { void BandwidthDialog::reject() {

View file

@ -22,34 +22,6 @@
#include "AnimSkeleton.h" #include "AnimSkeleton.h"
#include "IKTarget.h" #include "IKTarget.h"
void Rig::HeadParameters::dump() const {
qCDebug(animation, "HeadParameters =");
qCDebug(animation, " leanSideways = %0.5f", (double)leanSideways);
qCDebug(animation, " leanForward = %0.5f", (double)leanForward);
qCDebug(animation, " torsoTwist = %0.5f", (double)torsoTwist);
glm::vec3 axis = glm::axis(localHeadOrientation);
float theta = glm::angle(localHeadOrientation);
qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
axis = glm::axis(worldHeadOrientation);
theta = glm::angle(worldHeadOrientation);
qCDebug(animation, " localHead pitch = %.5f, yaw = %.5f, roll = %.5f", (double)localHeadPitch, (double)localHeadYaw, (double)localHeadRoll);
qCDebug(animation, " localHeadPosition = (%.5f, %.5f, %.5f)", (double)localHeadPosition.x, (double)localHeadPosition.y, (double)localHeadPosition.z);
qCDebug(animation, " isInHMD = %s", isInHMD ? "true" : "false");
qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
axis = glm::axis(modelRotation);
theta = glm::angle(modelRotation);
qCDebug(animation, " modelRotation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
qCDebug(animation, " modelTranslation = (%.5f, %.5f, %.5f)", (double)modelTranslation.x, (double)modelTranslation.y, (double)modelTranslation.z);
qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", (double)eyeLookAt.x, (double)eyeLookAt.y, (double)eyeLookAt.z);
qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", (double)eyeSaccade.x, (double)eyeSaccade.y, (double)eyeSaccade.z);
qCDebug(animation, " leanJointIndex = %.d", leanJointIndex);
qCDebug(animation, " neckJointIndex = %.d", neckJointIndex);
qCDebug(animation, " leftEyeJointIndex = %.d", leftEyeJointIndex);
qCDebug(animation, " rightEyeJointIndex = %.d", rightEyeJointIndex);
qCDebug(animation, " isTalking = %s", isTalking ? "true" : "false");
}
void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) { void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) {
for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) { for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) {
if (handle->getPriority() > (*it)->getPriority()) { if (handle->getPriority() > (*it)->getPriority()) {
@ -981,8 +953,6 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
_animVars.unset("lean"); _animVars.unset("lean");
} }
updateNeckJoint(params.neckJointIndex, params); updateNeckJoint(params.neckJointIndex, params);
updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
if (_enableAnimGraph) { if (_enableAnimGraph) {
_animVars.set("isTalking", params.isTalking); _animVars.set("isTalking", params.isTalking);
@ -990,6 +960,13 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
} }
} }
void Rig::updateFromEyeParameters(const EyeParameters& params) {
updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
updateEyeJoint(params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
}
static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f); static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f);
static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f); static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f);
static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f); static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
@ -1145,12 +1122,6 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
} }
} }
void Rig::updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation,
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
updateEyeJoint(leftEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade);
updateEyeJoint(rightEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade);
}
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
auto& state = _jointStates[index]; auto& state = _jointStates[index];

View file

@ -57,24 +57,26 @@ public:
float leanForward = 0.0f; // degrees float leanForward = 0.0f; // degrees
float torsoTwist = 0.0f; // degrees float torsoTwist = 0.0f; // degrees
bool enableLean = false; bool enableLean = false;
glm::quat modelRotation = glm::quat(); glm::quat worldHeadOrientation = glm::quat();
glm::quat localHeadOrientation = glm::quat(); glm::quat localHeadOrientation = glm::quat();
float localHeadPitch = 0.0f; // degrees float localHeadPitch = 0.0f; // degrees
float localHeadYaw = 0.0f; // degrees float localHeadYaw = 0.0f; // degrees
float localHeadRoll = 0.0f; // degrees float localHeadRoll = 0.0f; // degrees
glm::vec3 localHeadPosition = glm::vec3(); glm::vec3 localHeadPosition = glm::vec3();
bool isInHMD = false; bool isInHMD = false;
int leanJointIndex = -1;
int neckJointIndex = -1;
bool isTalking = false;
};
struct EyeParameters {
glm::quat worldHeadOrientation = glm::quat(); glm::quat worldHeadOrientation = glm::quat();
glm::vec3 eyeLookAt = glm::vec3(); // world space glm::vec3 eyeLookAt = glm::vec3(); // world space
glm::vec3 eyeSaccade = glm::vec3(); // world space glm::vec3 eyeSaccade = glm::vec3(); // world space
glm::vec3 modelTranslation = glm::vec3(); glm::vec3 modelTranslation = glm::vec3();
int leanJointIndex = -1; glm::quat modelRotation = glm::quat();
int neckJointIndex = -1;
int leftEyeJointIndex = -1; int leftEyeJointIndex = -1;
int rightEyeJointIndex = -1; int rightEyeJointIndex = -1;
bool isTalking = false;
void dump() const;
}; };
struct HandParameters { struct HandParameters {
@ -185,9 +187,7 @@ public:
bool getEnableAnimGraph() const { return _enableAnimGraph; } bool getEnableAnimGraph() const { return _enableAnimGraph; }
void updateFromHeadParameters(const HeadParameters& params, float dt); void updateFromHeadParameters(const HeadParameters& params, float dt);
void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, void updateFromEyeParameters(const EyeParameters& params);
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f));
void updateFromHandParameters(const HandParameters& params, float dt); void updateFromHandParameters(const HandParameters& params, float dt);
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,

View file

@ -22,7 +22,12 @@ AvatarHashMap::AvatarHashMap() {
connect(DependencyManager::get<NodeList>().data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged); connect(DependencyManager::get<NodeList>().data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
} }
void AvatarHashMap::withAvatarHash(std::function<void(const AvatarHash& hash)> callback) {
QReadLocker locker(&_hashLock);
callback(_avatarHash);
}
bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) { bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) {
QReadLocker locker(&_hashLock);
foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) { foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) {
glm::vec3 avatarPosition = sharedAvatar->getPosition(); glm::vec3 avatarPosition = sharedAvatar->getPosition();
float distance = glm::distance(avatarPosition, position); float distance = glm::distance(avatarPosition, position);
@ -43,6 +48,7 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
AvatarSharedPointer avatar = newSharedAvatar(); AvatarSharedPointer avatar = newSharedAvatar();
avatar->setSessionUUID(sessionUUID); avatar->setSessionUUID(sessionUUID);
avatar->setOwningAvatarMixer(mixerWeakPointer); avatar->setOwningAvatarMixer(mixerWeakPointer);
QWriteLocker locker(&_hashLock);
_avatarHash.insert(sessionUUID, avatar); _avatarHash.insert(sessionUUID, avatar);
return avatar; return avatar;
@ -134,6 +140,7 @@ void AvatarHashMap::processKillAvatar(QSharedPointer<NLPacket> packet, SharedNod
} }
void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) { void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) {
QWriteLocker locker(&_hashLock);
_avatarHash.remove(sessionUUID); _avatarHash.remove(sessionUUID);
} }

View file

@ -16,6 +16,7 @@
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
#include <QtCore/QUuid> #include <QtCore/QUuid>
#include <functional>
#include <memory> #include <memory>
#include <DependencyManager.h> #include <DependencyManager.h>
@ -30,7 +31,7 @@ class AvatarHashMap : public QObject, public Dependency {
SINGLETON_DEPENDENCY SINGLETON_DEPENDENCY
public: public:
const AvatarHash& getAvatarHash() { return _avatarHash; } void withAvatarHash(std::function<void(const AvatarHash& hash)>);
int size() { return _avatarHash.size(); } int size() { return _avatarHash.size(); }
public slots: public slots:
@ -52,6 +53,9 @@ protected:
virtual void removeAvatar(const QUuid& sessionUUID); virtual void removeAvatar(const QUuid& sessionUUID);
AvatarHash _avatarHash; AvatarHash _avatarHash;
// "Case-based safety": Most access to the _avatarHash is on the same thread. Write access is protected by a write-lock.
// If you read from a different thread, you must read-lock the _hashLock. (Scripted write access is not supported).
QReadWriteLock _hashLock;
private: private:
QUuid _lastOwnerSessionUUID; QUuid _lastOwnerSessionUUID;

View file

@ -47,6 +47,7 @@ public:
static QString actionTypeToString(EntityActionType actionType); static QString actionTypeToString(EntityActionType actionType);
virtual bool lifetimeIsOver() { return false; } virtual bool lifetimeIsOver() { return false; }
virtual quint64 getExpires() { return 0; }
bool locallyAddedButNotYetReceived = false; bool locallyAddedButNotYetReceived = false;

View file

@ -1790,9 +1790,17 @@ const QByteArray EntityItem::getActionDataInternal() const {
const QByteArray EntityItem::getActionData() const { const QByteArray EntityItem::getActionData() const {
QByteArray result; QByteArray result;
assertUnlocked(); assertUnlocked();
withReadLock([&] {
result = getActionDataInternal(); if (_actionDataDirty) {
withWriteLock([&] {
getActionDataInternal();
result = _allActionsDataCache;
}); });
} else {
withReadLock([&] {
result = _allActionsDataCache;
});
}
return result; return result;
} }

View file

@ -194,7 +194,7 @@ public:
glm::vec3 rotationMax; // radians glm::vec3 rotationMax; // radians
}; };
glm::mat4 getGlobalTransform(const QMultiHash<QString, QString>& _connectionParentMap, glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack) { const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack) {
glm::mat4 globalTransform; glm::mat4 globalTransform;
while (!nodeID.isNull()) { while (!nodeID.isNull()) {
@ -246,7 +246,7 @@ public:
glm::mat4 transformLink; glm::mat4 transformLink;
}; };
void appendModelIDs(const QString& parentID, const QMultiHash<QString, QString>& connectionChildMap, void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>& connectionChildMap,
QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs) { QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs) {
if (remainingModels.contains(parentID)) { if (remainingModels.contains(parentID)) {
modelIDs.append(parentID); modelIDs.append(parentID);
@ -331,7 +331,7 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIn
} }
} }
QString getTopModelID(const QMultiHash<QString, QString>& connectionParentMap, QString getTopModelID(const QMultiMap<QString, QString>& connectionParentMap,
const QHash<QString, FBXModel>& models, const QString& modelID) { const QHash<QString, FBXModel>& models, const QString& modelID) {
QString topID = modelID; QString topID = modelID;
forever { forever {
@ -361,7 +361,7 @@ public:
}; };
bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials, bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials,
const QHash<QString, QByteArray>& textureFilenames, const QMultiHash<QString, QString>& _connectionChildMap) { const QHash<QString, QByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
foreach (const QString& materialID, materials.keys()) { foreach (const QString& materialID, materials.keys()) {
foreach (const QString& childID, _connectionChildMap.values(materialID)) { foreach (const QString& childID, _connectionChildMap.values(materialID)) {
if (textureFilenames.contains(childID)) { if (textureFilenames.contains(childID)) {
@ -444,7 +444,7 @@ QByteArray fileOnUrl(const QByteArray& filenameString, const QString& url) {
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) { FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
const FBXNode& node = _fbxNode; const FBXNode& node = _fbxNode;
QHash<QString, ExtractedMesh> meshes; QMap<QString, ExtractedMesh> meshes;
QHash<QString, QString> modelIDsToNames; QHash<QString, QString> modelIDsToNames;
QHash<QString, int> meshIDsToMeshIndices; QHash<QString, int> meshIDsToMeshIndices;
QHash<QString, QString> ooChildToParent; QHash<QString, QString> ooChildToParent;
@ -1293,7 +1293,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// see if any materials have texture children // see if any materials have texture children
bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap); bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap);
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) { for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
ExtractedMesh& extracted = it.value(); ExtractedMesh& extracted = it.value();
extracted.mesh.meshExtents.reset(); extracted.mesh.meshExtents.reset();
@ -1641,5 +1641,3 @@ FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
return reader.extractFBXGeometry(mapping, url); return reader.extractFBXGeometry(mapping, url);
} }

View file

@ -413,8 +413,8 @@ public:
float _lightmapOffset = 0.0f; float _lightmapOffset = 0.0f;
float _lightmapLevel; float _lightmapLevel;
QMultiHash<QString, QString> _connectionParentMap; QMultiMap<QString, QString> _connectionParentMap;
QMultiHash<QString, QString> _connectionChildMap; QMultiMap<QString, QString> _connectionChildMap;
static glm::vec3 getVec3(const QVariantList& properties, int index); static glm::vec3 getVec3(const QVariantList& properties, int index);
static QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector); static QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector);

View file

@ -85,11 +85,11 @@ bool ObjectAction::updateArguments(QVariantMap arguments) {
quint64 previousExpires = _expires; quint64 previousExpires = _expires;
QString previousTag = _tag; QString previousTag = _tag;
bool lifetimeSet = true; bool ttlSet = true;
float lifetime = EntityActionInterface::extractFloatArgument("action", arguments, "lifetime", lifetimeSet, false); float ttl = EntityActionInterface::extractFloatArgument("action", arguments, "ttl", ttlSet, false);
if (lifetimeSet) { if (ttlSet) {
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
_expires = now + (quint64)(lifetime * USECS_PER_SECOND); _expires = now + (quint64)(ttl * USECS_PER_SECOND);
} else { } else {
_expires = 0; _expires = 0;
} }
@ -114,10 +114,10 @@ QVariantMap ObjectAction::getArguments() {
QVariantMap arguments; QVariantMap arguments;
withReadLock([&]{ withReadLock([&]{
if (_expires == 0) { if (_expires == 0) {
arguments["lifetime"] = 0.0f; arguments["ttl"] = 0.0f;
} else { } else {
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
arguments["lifetime"] = (float)(_expires - now) / (float)USECS_PER_SECOND; arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
} }
arguments["tag"] = _tag; arguments["tag"] = _tag;
}); });
@ -245,3 +245,31 @@ bool ObjectAction::lifetimeIsOver() {
} }
return false; return false;
} }
quint64 ObjectAction::localTimeToServerTime(quint64 timeValue) const {
// 0 indicates no expiration
if (timeValue == 0) {
return 0;
}
int 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;
}
int 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

@ -47,11 +47,10 @@ public:
virtual void deserialize(QByteArray serializedArguments) = 0; virtual void deserialize(QByteArray serializedArguments) = 0;
virtual bool lifetimeIsOver(); virtual bool lifetimeIsOver();
virtual quint64 getExpires() { return _expires; }
protected: protected:
int getEntityServerClockSkew() const;
virtual btRigidBody* getRigidBody(); virtual btRigidBody* getRigidBody();
virtual glm::vec3 getPosition(); virtual glm::vec3 getPosition();
virtual void setPosition(glm::vec3 position); virtual void setPosition(glm::vec3 position);
@ -68,6 +67,12 @@ protected:
quint64 _expires; // in seconds since epoch quint64 _expires; // in seconds since epoch
QString _tag; QString _tag;
quint64 localTimeToServerTime(quint64 timeValue) const;
quint64 serverTimeToLocalTime(quint64 timeValue) const;
private:
int getEntityServerClockSkew() const;
}; };
#endif // hifi_ObjectAction_h #endif // hifi_ObjectAction_h

View file

@ -160,7 +160,7 @@ QByteArray ObjectActionOffset::serialize() const {
dataStream << _linearDistance; dataStream << _linearDistance;
dataStream << _linearTimeScale; dataStream << _linearTimeScale;
dataStream << _positionalTargetSet; dataStream << _positionalTargetSet;
dataStream << _expires + getEntityServerClockSkew(); dataStream << localTimeToServerTime(_expires);
dataStream << _tag; dataStream << _tag;
}); });
@ -189,8 +189,11 @@ void ObjectActionOffset::deserialize(QByteArray serializedArguments) {
dataStream >> _linearDistance; dataStream >> _linearDistance;
dataStream >> _linearTimeScale; dataStream >> _linearTimeScale;
dataStream >> _positionalTargetSet; dataStream >> _positionalTargetSet;
dataStream >> _expires;
_expires -= getEntityServerClockSkew(); quint64 serverExpires;
dataStream >> serverExpires;
_expires = serverTimeToLocalTime(serverExpires);
dataStream >> _tag; dataStream >> _tag;
_active = true; _active = true;
}); });

View file

@ -198,7 +198,7 @@ QByteArray ObjectActionSpring::serialize() const {
dataStream << _rotationalTarget; dataStream << _rotationalTarget;
dataStream << _angularTimeScale; dataStream << _angularTimeScale;
dataStream << _rotationalTargetSet; dataStream << _rotationalTargetSet;
dataStream << _expires + getEntityServerClockSkew(); dataStream << localTimeToServerTime(_expires);
dataStream << _tag; dataStream << _tag;
}); });
@ -232,8 +232,10 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
dataStream >> _angularTimeScale; dataStream >> _angularTimeScale;
dataStream >> _rotationalTargetSet; dataStream >> _rotationalTargetSet;
dataStream >> _expires; quint64 serverExpires;
_expires -= getEntityServerClockSkew(); dataStream >> serverExpires;
_expires = serverTimeToLocalTime(serverExpires);
dataStream >> _tag; dataStream >> _tag;
_active = true; _active = true;

View file

@ -229,7 +229,7 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati
void MeshPartPayload::render(RenderArgs* args) const { void MeshPartPayload::render(RenderArgs* args) const {
PerformanceTimer perfTimer("MeshPartPayload::render"); PerformanceTimer perfTimer("MeshPartPayload::render");
if (!model->_readyWhenAdded) { if (!model->_readyWhenAdded || !model->_isVisible) {
return; // bail asap return; // bail asap
} }

View file

@ -101,7 +101,7 @@ static bool hasCorrectSyntax(const QScriptProgram& program) {
return true; return true;
} }
static bool hadUncauchtExceptions(QScriptEngine& engine, const QString& fileName) { static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {
if (engine.hasUncaughtException()) { if (engine.hasUncaughtException()) {
const auto backtrace = engine.uncaughtExceptionBacktrace(); const auto backtrace = engine.uncaughtExceptionBacktrace();
const auto exception = engine.uncaughtException().toString(); const auto exception = engine.uncaughtException().toString();
@ -615,7 +615,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
const auto result = QScriptEngine::evaluate(program); const auto result = QScriptEngine::evaluate(program);
--_evaluatesPending; --_evaluatesPending;
const auto hadUncaughtException = hadUncauchtExceptions(*this, program.fileName()); const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName());
if (_wantSignals) { if (_wantSignals) {
emit evaluationFinished(result, hadUncaughtException); emit evaluationFinished(result, hadUncaughtException);
} }
@ -684,9 +684,8 @@ void ScriptEngine::run() {
} }
lastUpdate = now; lastUpdate = now;
if (hadUncauchtExceptions(*this, _fileNameString)) { // Debug and clear exceptions
stop(); hadUncaughtExceptions(*this, _fileNameString);
}
} }
stopAllTimers(); // make sure all our timers are stopped if the script is ending stopAllTimers(); // make sure all our timers are stopped if the script is ending
@ -1021,7 +1020,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
QScriptEngine sandbox; QScriptEngine sandbox;
QScriptValue testConstructor = sandbox.evaluate(program); QScriptValue testConstructor = sandbox.evaluate(program);
if (hadUncauchtExceptions(sandbox, program.fileName())) { if (hadUncaughtExceptions(sandbox, program.fileName())) {
return; return;
} }

View file

@ -14,7 +14,7 @@
class ReadWriteLockable { class ReadWriteLockable {
public: public:
template <typename F> template <typename F>
bool withWriteLock(F f, bool require = true) { bool withWriteLock(F f, bool require = true) const {
if (!require) { if (!require) {
bool result = _lock.tryLockForWrite(); bool result = _lock.tryLockForWrite();
if (result) { if (result) {
@ -30,7 +30,7 @@ public:
} }
template <typename F> template <typename F>
bool withTryWriteLock(F f) { bool withTryWriteLock(F f) const {
return withWriteLock(f, false); return withWriteLock(f, false);
} }