History

Merge branch 'master' of https://github.com/highfidelity/hifi into removePropertiesFromRayPick

ZappoMan committed 9 years ago

Commit 246f3772 parents 9e287d4 73227f6364 files · +14004 −9659Browse files

Showing the changes to libraries/entities/src/EntityScriptingInterface.cpp (1 of 364 files). Show all

Unified · Split

libraries/entities/src/EntityScriptingInterface.cpp+163−13
@@ -8,8 +8,15 @@ · 7 unmodified lines
8// Distributed under the Apache License, Version 2.0.8// Distributed under the Apache License, Version 2.0.
9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10//10//
11
12#include <glm/gtc/matrix_transform.hpp>
13#include <glm/gtx/transform.hpp>
14
11#include "EntityScriptingInterface.h"15#include "EntityScriptingInterface.h"
12 16
17#include <QFutureWatcher>
18#include <QtConcurrent/QtConcurrentRun>
19
13#include "EntityItemID.h"20#include "EntityItemID.h"
14#include <VariantMapToScriptValue.h>21#include <VariantMapToScriptValue.h>
15#include <SharedUtil.h>22#include <SharedUtil.h>
@@ -289,13 +296,11 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit · 273 unmodified lines
289 296
290 results = entity->getProperties(desiredProperties);297 results = entity->getProperties(desiredProperties);
291 298
292 // TODO: improve sitting points and naturalDimensions in the future,299 // TODO: improve naturalDimensions in the future,
293 // for now we've included the old sitting points model behavior for entity types that are models300 // for now we've added this hack for setting natural dimensions of models
294 // we've also added this hack for setting natural dimensions of models
295 if (entity->getType() == EntityTypes::Model) {301 if (entity->getType() == EntityTypes::Model) {
296 const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity);302 const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity);
297 if (geometry) {303 if (geometry) {
298 results.setSittingPoints(geometry->sittingPoints);
299 Extents meshExtents = geometry->getUnscaledMeshExtents();304 Extents meshExtents = geometry->getUnscaledMeshExtents();
300 results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);305 results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
301 results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);306 results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
@@ -679,6 +684,118 @@ bool EntityScriptingInterface::reloadServerScripts(QUuid entityID) { · 377 unmodified lines
679 return client->reloadServerScript(entityID);684 return client->reloadServerScript(entityID);
680}685}
681 686
687bool EntityPropertyMetadataRequest::script(EntityItemID entityID, QScriptValue handler) {
688 using LocalScriptStatusRequest = QFutureWatcher<QVariant>;
689
690 LocalScriptStatusRequest* request = new LocalScriptStatusRequest;
691 QObject::connect(request, &LocalScriptStatusRequest::finished, _engine, [=]() mutable {
692 auto details = request->result().toMap();
693 QScriptValue err, result;
694 if (details.contains("isError")) {
695 if (!details.contains("message")) {
696 details["message"] = details["errorInfo"];
697 }
698 err = _engine->makeError(_engine->toScriptValue(details));
699 } else {
700 details["success"] = true;
701 result = _engine->toScriptValue(details);
702 }
703 callScopedHandlerObject(handler, err, result);
704 request->deleteLater();
705 });
706 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
707 entityScriptingInterface->withEntitiesScriptEngine([&](EntitiesScriptEngineProvider* entitiesScriptEngine) {
708 if (entitiesScriptEngine) {
709 request->setFuture(entitiesScriptEngine->getLocalEntityScriptDetails(entityID));
710 }
711 });
712 if (!request->isStarted()) {
713 request->deleteLater();
714 callScopedHandlerObject(handler, _engine->makeError("Entities Scripting Provider unavailable", "InternalError"), QScriptValue());
715 return false;
716 }
717 return true;
718}
719
720bool EntityPropertyMetadataRequest::serverScripts(EntityItemID entityID, QScriptValue handler) {
721 auto client = DependencyManager::get<EntityScriptClient>();
722 auto request = client->createScriptStatusRequest(entityID);
723 QPointer<BaseScriptEngine> engine = _engine;
724 QObject::connect(request, &GetScriptStatusRequest::finished, _engine, [=](GetScriptStatusRequest* request) mutable {
725 auto engine = _engine;
726 if (!engine) {
727 qCDebug(entities) << __FUNCTION__ << " -- engine destroyed while inflight" << entityID;
728 return;
729 }
730 QVariantMap details;
731 details["success"] = request->getResponseReceived();
732 details["isRunning"] = request->getIsRunning();
733 details["status"] = EntityScriptStatus_::valueToKey(request->getStatus()).toLower();
734 details["errorInfo"] = request->getErrorInfo();
735
736 QScriptValue err, result;
737 if (!details["success"].toBool()) {
738 if (!details.contains("message") && details.contains("errorInfo")) {
739 details["message"] = details["errorInfo"];
740 }
741 if (details["message"].toString().isEmpty()) {
742 details["message"] = "entity server script details not found";
743 }
744 err = engine->makeError(engine->toScriptValue(details));
745 } else {
746 result = engine->toScriptValue(details);
747 }
748 callScopedHandlerObject(handler, err, result);
749 request->deleteLater();
750 });
751 request->start();
752 return true;
753}
754
755bool EntityScriptingInterface::queryPropertyMetadata(QUuid entityID, QScriptValue property, QScriptValue scopeOrCallback, QScriptValue methodOrName) {
756 auto name = property.toString();
757 auto handler = makeScopedHandlerObject(scopeOrCallback, methodOrName);
758 QPointer<BaseScriptEngine> engine = dynamic_cast<BaseScriptEngine*>(handler.engine());
759 if (!engine) {
760 qCDebug(entities) << "queryPropertyMetadata without detectable engine" << entityID << name;
761 return false;
762 }
763#ifdef DEBUG_ENGINE_STATE
764 connect(engine, &QObject::destroyed, this, [=]() {
765 qDebug() << "queryPropertyMetadata -- engine destroyed!" << (!engine ? "nullptr" : "engine");
766 });
767#endif
768 if (!handler.property("callback").isFunction()) {
769 qDebug() << "!handler.callback.isFunction" << engine;
770 engine->raiseException(engine->makeError("callback is not a function", "TypeError"));
771 return false;
772 }
773
774 // NOTE: this approach is a work-in-progress and for now just meant to work 100% correctly and provide
775 // some initial structure for organizing metadata adapters around.
776
777 // The extra layer of indirection is *essential* because in real world conditions errors are often introduced
778 // by accident and sometimes without exact memory of "what just changed."
779
780 // Here the scripter only needs to know an entityID and a property name -- which means all scripters can
781 // level this method when stuck in dead-end scenarios or to learn more about "magic" Entity properties
782 // like .script that work in terms of side-effects.
783
784 // This is an async callback pattern -- so if needed C++ can easily throttle or restrict queries later.
785
786 EntityPropertyMetadataRequest request(engine);
787
788 if (name == "script") {
789 return request.script(entityID, handler);
790 } else if (name == "serverScripts") {
791 return request.serverScripts(entityID, handler);
792 } else {
793 engine->raiseException(engine->makeError("metadata for property " + name + " is not yet queryable"));
794 engine->maybeEmitUncaughtException(__FUNCTION__);
795 return false;
796 }
797}
798
682bool EntityScriptingInterface::getServerScriptStatus(QUuid entityID, QScriptValue callback) {799bool EntityScriptingInterface::getServerScriptStatus(QUuid entityID, QScriptValue callback) {
683 auto client = DependencyManager::get<EntityScriptClient>();800 auto client = DependencyManager::get<EntityScriptClient>();
684 auto request = client->createScriptStatusRequest(entityID);801 auto request = client->createScriptStatusRequest(entityID);
@@ -806,8 +923,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra · 121 unmodified lines
806 }923 }
807}924}
808 925
809bool EntityScriptingInterface::setVoxels(QUuid entityID,926bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor) {
810 std::function<bool(PolyVoxEntityItem&)> actor) {
811 PROFILE_RANGE(script_entities, __FUNCTION__);927 PROFILE_RANGE(script_entities, __FUNCTION__);
812 928
813 if (!_entityTree) {929 if (!_entityTree) {
@@ -873,11 +989,9 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(Line · 59 unmodified lines
873 return success;989 return success;
874}990}
875 991
876
877bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {992bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
878 PROFILE_RANGE(script_entities, __FUNCTION__);993 PROFILE_RANGE(script_entities, __FUNCTION__);
879 994 return polyVoxWorker(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
880 return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
881 return polyVoxEntity.setSphere(center, radius, value);995 return polyVoxEntity.setSphere(center, radius, value);
882 });996 });
883}997}
@@ -887,7 +1001,7 @@ bool EntityScriptingInterface::setVoxelCapsule(QUuid entityID, · 3 unmodified lines
887 float radius, int value) {1001 float radius, int value) {
888 PROFILE_RANGE(script_entities, __FUNCTION__);1002 PROFILE_RANGE(script_entities, __FUNCTION__);
889 1003
890 return setVoxels(entityID, [start, end, radius, value](PolyVoxEntityItem& polyVoxEntity) {1004 return polyVoxWorker(entityID, [start, end, radius, value](PolyVoxEntityItem& polyVoxEntity) {
891 return polyVoxEntity.setCapsule(start, end, radius, value);1005 return polyVoxEntity.setCapsule(start, end, radius, value);
892 });1006 });
893}1007}
@@ -895,7 +1009,7 @@ bool EntityScriptingInterface::setVoxelCapsule(QUuid entityID, · 1 unmodified line
895bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) {1009bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) {
896 PROFILE_RANGE(script_entities, __FUNCTION__);1010 PROFILE_RANGE(script_entities, __FUNCTION__);
897 1011
898 return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) {1012 return polyVoxWorker(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) {
899 return polyVoxEntity.setVoxelInVolume(position, value);1013 return polyVoxEntity.setVoxelInVolume(position, value);
900 });1014 });
901}1015}
@@ -903,7 +1017,7 @@ bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& positio · 1 unmodified line
903bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {1017bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
904 PROFILE_RANGE(script_entities, __FUNCTION__);1018 PROFILE_RANGE(script_entities, __FUNCTION__);
905 1019
906 return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) {1020 return polyVoxWorker(entityID, [value](PolyVoxEntityItem& polyVoxEntity) {
907 return polyVoxEntity.setAll(value);1021 return polyVoxEntity.setAll(value);
908 });1022 });
909}1023}
@@ -912,11 +1026,30 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 · 2 unmodified lines
912 const glm::vec3& cuboidSize, int value) {1026 const glm::vec3& cuboidSize, int value) {
913 PROFILE_RANGE(script_entities, __FUNCTION__);1027 PROFILE_RANGE(script_entities, __FUNCTION__);
914 1028
915 return setVoxels(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) {1029 return polyVoxWorker(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) {
916 return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value);1030 return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value);
917 });1031 });
918}1032}
919 1033
1034void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) {
1035 PROFILE_RANGE(script_entities, __FUNCTION__);
1036
1037 bool success { false };
1038 QScriptValue mesh { false };
1039
1040 polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable {
1041 if (polyVoxEntity.getOnCount() == 0) {
1042 success = true;
1043 } else {
1044 success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh);
1045 }
1046 return true;
1047 });
1048
1049 QScriptValueList args { mesh, success };
1050 callback.call(QScriptValue(), args);
1051}
1052
920bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {1053bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
921 PROFILE_RANGE(script_entities, __FUNCTION__);1054 PROFILE_RANGE(script_entities, __FUNCTION__);
922 1055
@@ -1532,3 +1665,20 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons · 609 unmodified lines
1532 AABox aaBox(low, dimensions);1665 AABox aaBox(low, dimensions);
1533 return aaBox.findCapsulePenetration(start, end, radius, penetration);1666 return aaBox.findCapsulePenetration(start, end, radius, penetration);
1534}1667}
1668
1669glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
1670 glm::mat4 result;
1671 if (_entityTree) {
1672 _entityTree->withReadLock([&] {
1673 EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
1674 if (entity) {
1675 glm::mat4 translation = glm::translate(entity->getPosition());
1676 glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
1677 glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT -
1678 entity->getRegistrationPoint());
1679 result = translation * rotation * registration;
1680 }
1681 });
1682 }
1683 return result;
1684}