From 4e83301c65cedbd465bdd7c26c309598c9db2a6d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 31 Mar 2015 18:27:46 -0700 Subject: [PATCH 1/3] add a bool value to Node which indicates if it is allowed to rez new entities --- .../src/AssignmentClientMonitor.cpp | 2 +- .../resources/describe-settings.json | 7 ++++ domain-server/src/DomainServer.cpp | 18 +++++++++- examples/dice.js | 36 +++++++++++-------- .../entities/src/EntityScriptingInterface.cpp | 6 +++- .../entities/src/EntityScriptingInterface.h | 4 +++ libraries/entities/src/EntityTree.cpp | 14 ++++---- libraries/networking/src/LimitedNodeList.cpp | 15 ++++++-- libraries/networking/src/LimitedNodeList.h | 8 ++++- libraries/networking/src/Node.cpp | 7 ++-- libraries/networking/src/Node.h | 6 +++- libraries/networking/src/NodeList.cpp | 10 ++++-- 12 files changed, 101 insertions(+), 32 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 1280b55b12..d591087acd 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -180,7 +180,7 @@ void AssignmentClientMonitor::readPendingDatagrams() { senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { if (!packetUUID.isNull()) { matchingNode = DependencyManager::get()->addOrUpdateNode - (packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false); + (packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false, false); AssignmentClientChildData *childData = new AssignmentClientChildData("unknown"); matchingNode->setLinkedData(childData); } else { diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 0082bd84ae..e694afa1da 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -95,6 +95,13 @@ "can_set": true } ] + }, + { + "name": "editors_are_rezzers", + "type": "checkbox", + "label": "Only editors can create new entities", + "help": "When checked, only those who can edit the domain can create new entites.", + "default": false } ] }, diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0918b85a63..8c734e20a1 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -46,6 +46,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity"; const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors"; +const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers"; DomainServer::DomainServer(int argc, char* argv[]) : @@ -645,9 +646,23 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList(); bool canAdjustLocks = allowedEditors.isEmpty() || allowedEditors.contains(username); + const QVariant* editorsAreRezzersVariant = + valueForKeyPath(_settingsManager.getSettingsMap(), EDITORS_ARE_REZZERS_KEYPATH); + + bool onlyEditorsAreRezzers = false; + if (editorsAreRezzersVariant) { + onlyEditorsAreRezzers = editorsAreRezzersVariant->toBool(); + } + + bool canRez = true; + if (onlyEditorsAreRezzers) { + canRez = canAdjustLocks; + } + SharedNodePointer newNode = DependencyManager::get()->addOrUpdateNode(nodeUUID, nodeType, - publicSockAddr, localSockAddr, canAdjustLocks); + publicSockAddr, localSockAddr, + canAdjustLocks, canRez); // when the newNode is created the linked data is also created // if this was a static assignment set the UUID, set the sendingSockAddr DomainServerNodeData* nodeData = reinterpret_cast(newNode->getLinkedData()); @@ -902,6 +917,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append); broadcastDataStream << node->getUUID(); broadcastDataStream << node->getCanAdjustLocks(); + broadcastDataStream << node->getCanRez(); int numBroadcastPacketLeadBytes = broadcastDataStream.device()->pos(); diff --git a/examples/dice.js b/examples/dice.js index 2aefcf90fe..a1362e13e9 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -23,6 +23,8 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var rollSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/dice/diceRoll.wav"); +var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to create new Objects." + var screenSize = Controller.getViewportDimensions(); var offButton = Overlays.addOverlay("image", { x: screenSize.x - 48, @@ -49,20 +51,26 @@ var LIFETIME = 300; var MAX_ANGULAR_SPEED = Math.PI; function shootDice(position, velocity) { - for (var i = 0; i < NUMBER_OF_DICE; i++) { - dice.push(Entities.addEntity( - { type: "Model", - modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx", - position: position, - velocity: velocity, - rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), - angularVelocity: { x: Math.random() * MAX_ANGULAR_SPEED, y: Math.random() * MAX_ANGULAR_SPEED, z: Math.random() * MAX_ANGULAR_SPEED }, - lifetime: LIFETIME, - gravity: { x: 0, y: GRAVITY, z: 0 }, - shapeType: "box", - collisionsWillMove: true - })); - position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation())))); + if (!Entities.canRez()) { + Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG); + } else { + for (var i = 0; i < NUMBER_OF_DICE; i++) { + dice.push(Entities.addEntity( + { type: "Model", + modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx", + position: position, + velocity: velocity, + rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), + angularVelocity: { x: Math.random() * MAX_ANGULAR_SPEED, + y: Math.random() * MAX_ANGULAR_SPEED, + z: Math.random() * MAX_ANGULAR_SPEED }, + lifetime: LIFETIME, + gravity: { x: 0, y: GRAVITY, z: 0 }, + shapeType: "box", + collisionsWillMove: true + })); + position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation())))); + } } } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 5624e0765b..c41b9a5c41 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -23,6 +23,7 @@ EntityScriptingInterface::EntityScriptingInterface() : { auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::canAdjustLocksChanged, this, &EntityScriptingInterface::canAdjustLocksChanged); + connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptingInterface::canRezChanged); } void EntityScriptingInterface::queueEntityMessage(PacketType packetType, @@ -30,12 +31,15 @@ void EntityScriptingInterface::queueEntityMessage(PacketType packetType, getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties); } - bool EntityScriptingInterface::canAdjustLocks() { auto nodeList = DependencyManager::get(); return nodeList->getThisNodeCanAdjustLocks(); } +bool EntityScriptingInterface::canRez() { + auto nodeList = DependencyManager::get(); + return nodeList->getThisNodeCanRez(); +} void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { if (_entityTree) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 5e75e2ae0d..075f5a712b 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -66,6 +66,9 @@ public slots: // returns true if the DomainServer will allow this Node/Avatar to make changes Q_INVOKABLE bool canAdjustLocks(); + // returns true if the DomainServer will allow this Node/Avatar to rez new entities + Q_INVOKABLE bool canRez(); + /// adds a model with the specific properties Q_INVOKABLE EntityItemID addEntity(const EntityItemProperties& properties); @@ -117,6 +120,7 @@ signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void canAdjustLocksChanged(bool canAdjustLocks); + void canRezChanged(bool canRez); void mousePressOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void mouseMoveOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index cb5d43693d..c4b12f2059 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -659,12 +659,14 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char qDebug() << "User attempted to edit an unknown entity. ID:" << entityItemID; } } else { - // this is a new entity... assign a new entityID - entityItemID = assignEntityID(entityItemID); - EntityItem* newEntity = addEntity(entityItemID, properties); - if (newEntity) { - newEntity->markAsChangedOnServer(); - notifyNewlyCreatedEntity(*newEntity, senderNode); + if (senderNode->getCanRez()) { + // this is a new entity... assign a new entityID + entityItemID = assignEntityID(entityItemID); + EntityItem* newEntity = addEntity(entityItemID, properties); + if (newEntity) { + newEntity->markAsChangedOnServer(); + notifyNewlyCreatedEntity(*newEntity, senderNode); + } } } } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 57977910c7..c69fe2ad96 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -49,7 +49,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _publicSockAddr(), _stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT), _packetStatTimer(), - _thisNodeCanAdjustLocks(false) + _thisNodeCanAdjustLocks(false), + _thisNodeCanRez(true) { static bool firstCall = true; if (firstCall) { @@ -108,6 +109,13 @@ void LimitedNodeList::setThisNodeCanAdjustLocks(bool canAdjustLocks) { } } +void LimitedNodeList::setThisNodeCanRez(bool canRez) { + if (_thisNodeCanRez != canRez) { + _thisNodeCanRez = canRez; + emit canRezChanged(canRez); + } +} + QUdpSocket& LimitedNodeList::getDTLSSocket() { if (!_dtlsSocket) { // DTLS socket getter called but no DTLS socket exists, create it now @@ -417,7 +425,7 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) { SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - bool canAdjustLocks) { + bool canAdjustLocks, bool canRez) { NodeHash::const_iterator it = _nodeHash.find(uuid); if (it != _nodeHash.end()) { @@ -426,11 +434,12 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t matchingNode->setPublicSocket(publicSocket); matchingNode->setLocalSocket(localSocket); matchingNode->setCanAdjustLocks(canAdjustLocks); + matchingNode->setCanRez(canRez); return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks, canRez); SharedNodePointer newNodePointer(newNode); _nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 532e8ffcf4..3fa1f80bf4 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -86,6 +86,9 @@ public: bool getThisNodeCanAdjustLocks() const { return _thisNodeCanAdjustLocks; } void setThisNodeCanAdjustLocks(bool canAdjustLocks); + + bool getThisNodeCanRez() const { return _thisNodeCanRez; } + void setThisNodeCanRez(bool canRez); void rebindNodeSocket(); QUdpSocket& getNodeSocket() { return _nodeSocket; } @@ -116,7 +119,8 @@ public: SharedNodePointer sendingNodeForPacket(const QByteArray& packet); SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, - const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks); + const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, + bool canAdjustLocks, bool canRez); const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; } const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; } @@ -208,6 +212,7 @@ signals: void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); void canAdjustLocksChanged(bool canAdjustLocks); + void canRezChanged(bool canRez); void dataSent(const quint8 channel_type, const int bytes); void dataReceived(const quint8 channel_type, const int bytes); @@ -243,6 +248,7 @@ protected: QElapsedTimer _packetStatTimer; bool _thisNodeCanAdjustLocks; + bool _thisNodeCanRez; template void eachNodeHashIterator(IteratorLambda functor) { diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 0304defb55..defcd0035b 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -41,7 +41,7 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { } Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, - const HifiSockAddr& localSocket, bool canAdjustLocks) : + const HifiSockAddr& localSocket, bool canAdjustLocks, bool canRez) : NetworkPeer(uuid, publicSocket, localSocket), _type(type), _activeSocket(NULL), @@ -53,7 +53,8 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, _clockSkewUsec(0), _mutex(), _clockSkewMovingPercentile(30, 0.8f), // moving 80th percentile of 30 samples - _canAdjustLocks(canAdjustLocks) + _canAdjustLocks(canAdjustLocks), + _canRez(canRez) { } @@ -133,6 +134,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._publicSocket; out << node._localSocket; out << node._canAdjustLocks; + out << node._canRez; return out; } @@ -143,6 +145,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) { in >> node._publicSocket; in >> node._localSocket; in >> node._canAdjustLocks; + in >> node._canRez; return in; } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index fa77540c96..420c52b423 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -45,7 +45,7 @@ class Node : public NetworkPeer { Q_OBJECT public: Node(const QUuid& uuid, NodeType_t type, - const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks); + const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks, bool canRez); ~Node(); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } @@ -79,6 +79,9 @@ public: void setCanAdjustLocks(bool canAdjustLocks) { _canAdjustLocks = canAdjustLocks; } bool getCanAdjustLocks() { return _canAdjustLocks; } + + void setCanRez(bool canRez) { _canRez = canRez; } + bool getCanRez() { return _canRez; } void activatePublicSocket(); void activateLocalSocket(); @@ -105,6 +108,7 @@ private: QMutex _mutex; MovingPercentile _clockSkewMovingPercentile; bool _canAdjustLocks; + bool _canRez; }; QDebug operator<<(QDebug debug, const Node &message); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 83424d7688..307ba93c88 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -403,6 +403,10 @@ int NodeList::processDomainServerList(const QByteArray& packet) { bool thisNodeCanAdjustLocks; packetStream >> thisNodeCanAdjustLocks; setThisNodeCanAdjustLocks(thisNodeCanAdjustLocks); + + bool thisNodeCanRez; + packetStream >> thisNodeCanRez; + setThisNodeCanRez(thisNodeCanRez); // pull each node in the packet while(packetStream.device()->pos() < packet.size()) { @@ -411,8 +415,9 @@ int NodeList::processDomainServerList(const QByteArray& packet) { QUuid nodeUUID, connectionUUID; HifiSockAddr nodePublicSocket, nodeLocalSocket; bool canAdjustLocks; + bool canRez; - packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> canAdjustLocks; + packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> canAdjustLocks >> canRez; // if the public socket address is 0 then it's reachable at the same IP // as the domain server @@ -420,7 +425,8 @@ int NodeList::processDomainServerList(const QByteArray& packet) { nodePublicSocket.setAddress(_domainHandler.getIP()); } - SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket, canAdjustLocks); + SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, + nodeLocalSocket, canAdjustLocks, canRez); packetStream >> connectionUUID; node->setConnectionSecret(connectionUUID); From 8bca8ad4efc5221e8a73c5ddefdf5c74c40f630b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 31 Mar 2015 18:37:42 -0700 Subject: [PATCH 2/3] bump protocol versions for PacketTypeDomainList and PacketTypeDomainListRequest --- libraries/networking/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 78a27af686..af6308d72f 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -64,7 +64,7 @@ PacketVersion versionForPacketType(PacketType type) { return 2; case PacketTypeDomainList: case PacketTypeDomainListRequest: - return 4; + return 5; case PacketTypeCreateAssignment: case PacketTypeRequestAssignment: return 2; From 04901e99fc3f4909836e6758fa36d2d1d2085bbe Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 31 Mar 2015 18:41:29 -0700 Subject: [PATCH 3/3] fix error message --- examples/dice.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dice.js b/examples/dice.js index a1362e13e9..6943c926ae 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -23,7 +23,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var rollSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/dice/diceRoll.wav"); -var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to create new Objects." +var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to create new objects." var screenSize = Controller.getViewportDimensions(); var offButton = Overlays.addOverlay("image", {