mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 08:53:10 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into polyvox
This commit is contained in:
commit
72e227eefe
72 changed files with 1134 additions and 1647 deletions
|
@ -73,17 +73,6 @@ void Agent::readPendingDatagrams() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (datagramPacketType == PacketTypeEntityAddResponse) {
|
|
||||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
|
||||||
EntityItemID::handleAddEntityResponse(receivedPacket);
|
|
||||||
|
|
||||||
// also give our local entity tree a chance to remap any internal locally created entities
|
|
||||||
_entityViewer.getTree()->handleAddEntityResponse(receivedPacket);
|
|
||||||
|
|
||||||
// Make sure our Node and NodeList knows we've heard from this node.
|
|
||||||
SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
|
|
||||||
sourceNode->setLastHeardMicrostamp(usecTimestampNow());
|
|
||||||
|
|
||||||
} else if (datagramPacketType == PacketTypeOctreeStats
|
} else if (datagramPacketType == PacketTypeOctreeStats
|
||||||
|| datagramPacketType == PacketTypeEntityData
|
|| datagramPacketType == PacketTypeEntityData
|
||||||
|| datagramPacketType == PacketTypeEntityErase
|
|| datagramPacketType == PacketTypeEntityErase
|
||||||
|
|
|
@ -43,8 +43,7 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||||
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
|
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
|
||||||
quint16 assignmentMonitorPort) :
|
quint16 assignmentMonitorPort) :
|
||||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
|
||||||
_localASPortSharedMem(NULL)
|
|
||||||
{
|
{
|
||||||
LogUtils::init();
|
LogUtils::init();
|
||||||
|
|
||||||
|
@ -181,8 +180,7 @@ void AssignmentClient::sendAssignmentRequest() {
|
||||||
if (_assignmentServerHostname == "localhost") {
|
if (_assignmentServerHostname == "localhost") {
|
||||||
// we want to check again for the local domain-server port in case the DS has restarted
|
// we want to check again for the local domain-server port in case the DS has restarted
|
||||||
quint16 localAssignmentServerPort;
|
quint16 localAssignmentServerPort;
|
||||||
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem,
|
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) {
|
||||||
localAssignmentServerPort)) {
|
|
||||||
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||||
qDebug() << "Port for local assignment server read from shared memory is"
|
qDebug() << "Port for local assignment server read from shared memory is"
|
||||||
<< localAssignmentServerPort;
|
<< localAssignmentServerPort;
|
||||||
|
@ -190,7 +188,11 @@ void AssignmentClient::sendAssignmentRequest() {
|
||||||
_assignmentServerSocket.setPort(localAssignmentServerPort);
|
_assignmentServerSocket.setPort(localAssignmentServerPort);
|
||||||
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
nodeList->setAssignmentServerSocket(_assignmentServerSocket);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Failed to read local assignment server port from shared memory"
|
||||||
|
<< "- will send assignment request to previous assignment server socket.";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeList->sendAssignment(_requestAssignment);
|
nodeList->sendAssignment(_requestAssignment);
|
||||||
|
|
|
@ -44,7 +44,6 @@ private:
|
||||||
QPointer<ThreadedAssignment> _currentAssignment;
|
QPointer<ThreadedAssignment> _currentAssignment;
|
||||||
QString _assignmentServerHostname;
|
QString _assignmentServerHostname;
|
||||||
HifiSockAddr _assignmentServerSocket;
|
HifiSockAddr _assignmentServerSocket;
|
||||||
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
|
||||||
QTimer _requestTimer; // timer for requesting and assignment
|
QTimer _requestTimer; // timer for requesting and assignment
|
||||||
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
||||||
|
|
||||||
|
|
|
@ -60,30 +60,6 @@ void EntityServer::beforeRun() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) {
|
void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) {
|
||||||
|
|
||||||
unsigned char outputBuffer[MAX_PACKET_SIZE];
|
|
||||||
unsigned char* copyAt = outputBuffer;
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
|
||||||
|
|
||||||
int numBytesPacketHeader = nodeList->populatePacketHeader(reinterpret_cast<char*>(outputBuffer), PacketTypeEntityAddResponse);
|
|
||||||
int packetLength = numBytesPacketHeader;
|
|
||||||
copyAt += numBytesPacketHeader;
|
|
||||||
|
|
||||||
// encode the creatorTokenID
|
|
||||||
uint32_t creatorTokenID = newEntity.getCreatorTokenID();
|
|
||||||
memcpy(copyAt, &creatorTokenID, sizeof(creatorTokenID));
|
|
||||||
copyAt += sizeof(creatorTokenID);
|
|
||||||
packetLength += sizeof(creatorTokenID);
|
|
||||||
|
|
||||||
// encode the entity ID
|
|
||||||
QUuid entityID = newEntity.getID();
|
|
||||||
QByteArray encodedID = entityID.toRfc4122();
|
|
||||||
memcpy(copyAt, encodedID.constData(), encodedID.size());
|
|
||||||
copyAt += sizeof(entityID);
|
|
||||||
packetLength += sizeof(entityID);
|
|
||||||
|
|
||||||
nodeList->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
22
domain-server/resources/web/css/bootstrap-switch.min.css
vendored
Executable file
22
domain-server/resources/web/css/bootstrap-switch.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -109,6 +109,13 @@ table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* styling for bootstrap-switch toggles */
|
||||||
|
.checkbox-help {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSS only spinner for AJAX requests */
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
margin: 30px auto 0;
|
margin: 30px auto 0;
|
||||||
width: 70px;
|
width: 70px;
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||||
<link href="/css/style.css" rel="stylesheet" media="screen">
|
<link href="/css/style.css" rel="stylesheet" media="screen">
|
||||||
<link href="/css/sweetalert.css" rel="stylesheet" media="screen">
|
<link href="/css/sweetalert.css" rel="stylesheet" media="screen">
|
||||||
|
<link href="/css/bootstrap-switch.min.css" rel="stylesheet" media="screen">
|
||||||
<link href="/stats/css/json.human.css" rel="stylesheet" media="screen">
|
<link href="/stats/css/json.human.css" rel="stylesheet" media="screen">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-default" role="navigation">
|
<nav class="navbar navbar-default" role="navigation">
|
||||||
|
|
|
@ -99,7 +99,8 @@
|
||||||
<script src='/js/underscore-min.js'></script>
|
<script src='/js/underscore-min.js'></script>
|
||||||
<script src='/js/underscore-keypath.min.js'></script>
|
<script src='/js/underscore-keypath.min.js'></script>
|
||||||
<script src='/js/bootbox.min.js'></script>
|
<script src='/js/bootbox.min.js'></script>
|
||||||
<script src='/js/sweetalert.min.js'></script>
|
<script src='js/bootstrap-switch.min.js'></script>
|
||||||
<script src='/js/settings.js'></script>
|
<script src='js/sweetalert.min.js'></script>
|
||||||
<script src='/js/form2js.min.js'></script>
|
<script src='js/settings.js'></script>
|
||||||
|
<script src='js/form2js.min.js'></script>
|
||||||
<!--#include virtual="page-end.html"-->
|
<!--#include virtual="page-end.html"-->
|
||||||
|
|
22
domain-server/resources/web/settings/js/bootstrap-switch.min.js
vendored
Executable file
22
domain-server/resources/web/settings/js/bootstrap-switch.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -60,10 +60,15 @@ var viewHelpers = {
|
||||||
if (setting.label) {
|
if (setting.label) {
|
||||||
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
|
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
|
||||||
}
|
}
|
||||||
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
|
|
||||||
form_group += "<label for='" + keypath + "'>"
|
form_group += "<div class='toggle-checkbox-container" + (isLocked ? " disabled" : "") + "'>"
|
||||||
form_group += "<input type='checkbox'" + common_attrs() + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
|
form_group += "<input type='checkbox'" + common_attrs('toggle-checkbox') + (setting_value ? "checked" : "")
|
||||||
form_group += " " + setting.help + "</label>";
|
form_group += (isLocked ? " disabled" : "") + "/>"
|
||||||
|
|
||||||
|
if (setting.help) {
|
||||||
|
form_group += "<span class='help-block checkbox-help'>" + setting.help + "</span>";
|
||||||
|
}
|
||||||
|
|
||||||
form_group += "</div>"
|
form_group += "</div>"
|
||||||
} else {
|
} else {
|
||||||
input_type = _.has(setting, 'type') ? setting.type : "text"
|
input_type = _.has(setting, 'type') ? setting.type : "text"
|
||||||
|
@ -201,10 +206,17 @@ $(document).ready(function(){
|
||||||
|
|
||||||
$('#' + Settings.FORM_ID).on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){
|
$('#' + Settings.FORM_ID).on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){
|
||||||
// this input was changed, add the changed data attribute to it
|
// this input was changed, add the changed data attribute to it
|
||||||
$(this).attr('data-changed', true)
|
$(this).attr('data-changed', true);
|
||||||
|
|
||||||
badgeSidebarForDifferences($(this))
|
badgeSidebarForDifferences($(this));
|
||||||
})
|
});
|
||||||
|
|
||||||
|
$('#' + Settings.FORM_ID).on('switchChange.bootstrapSwitch', 'input.toggle-checkbox', function(){
|
||||||
|
// this checkbox was changed, add the changed data attribute to it
|
||||||
|
$(this).attr('data-changed', true);
|
||||||
|
|
||||||
|
badgeSidebarForDifferences($(this));
|
||||||
|
});
|
||||||
|
|
||||||
$('.advanced-toggle').click(function(){
|
$('.advanced-toggle').click(function(){
|
||||||
Settings.showAdvanced = !Settings.showAdvanced
|
Settings.showAdvanced = !Settings.showAdvanced
|
||||||
|
@ -735,6 +747,9 @@ function reloadSettings() {
|
||||||
// call our method to setup the place names table
|
// call our method to setup the place names table
|
||||||
setupPlacesTable();
|
setupPlacesTable();
|
||||||
|
|
||||||
|
// setup any bootstrap switches
|
||||||
|
$('.toggle-checkbox').bootstrapSwitch();
|
||||||
|
|
||||||
// add tooltip to locked settings
|
// add tooltip to locked settings
|
||||||
$('label.locked').tooltip({
|
$('label.locked').tooltip({
|
||||||
placement: 'right',
|
placement: 'right',
|
|
@ -44,13 +44,10 @@ int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
||||||
|
|
||||||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io";
|
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 MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
|
||||||
const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors";
|
const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors";
|
||||||
const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers";
|
const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers";
|
||||||
|
|
||||||
|
|
||||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
QCoreApplication(argc, argv),
|
QCoreApplication(argc, argv),
|
||||||
_httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
_httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||||
|
@ -776,9 +773,8 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
|
||||||
const HifiSockAddr& senderSockAddr,
|
const HifiSockAddr& senderSockAddr,
|
||||||
QString& reasonReturn) {
|
QString& reasonReturn) {
|
||||||
|
|
||||||
const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(),
|
bool isRestrictingAccess =
|
||||||
ALLOWED_USERS_SETTINGS_KEYPATH);
|
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
||||||
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
|
|
||||||
|
|
||||||
// we always let in a user who is sending a packet from our local socket or from the localhost address
|
// we always let in a user who is sending a packet from our local socket or from the localhost address
|
||||||
if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|
if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
|
||||||
|
@ -786,45 +782,50 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowedUsers.count() > 0) {
|
if (isRestrictingAccess) {
|
||||||
|
|
||||||
|
QStringList allowedUsers =
|
||||||
|
_settingsManager.valueOrDefaultValueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH).toStringList();
|
||||||
|
|
||||||
if (allowedUsers.contains(username, Qt::CaseInsensitive)) {
|
if (allowedUsers.contains(username, Qt::CaseInsensitive)) {
|
||||||
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
if (!verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Connect request denied for user" << username << "not in allowed users list.";
|
qDebug() << "Connect request denied for user" << username << "not in allowed users list.";
|
||||||
reasonReturn = "User not on whitelist.";
|
reasonReturn = "User not on whitelist.";
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// we have no allowed user list.
|
|
||||||
|
|
||||||
// if this user is in the editors list, exempt them from the max-capacity check
|
return false;
|
||||||
const QVariant* allowedEditorsVariant =
|
|
||||||
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
|
|
||||||
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
|
|
||||||
if (allowedEditors.contains(username)) {
|
|
||||||
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we haven't reached max-capacity, let them in.
|
|
||||||
const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
|
|
||||||
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
|
|
||||||
if (maximumUserCapacity > 0) {
|
|
||||||
unsigned int connectedUsers = countConnectedUsers();
|
|
||||||
if (connectedUsers >= maximumUserCapacity) {
|
|
||||||
// too many users, deny the new connection.
|
|
||||||
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection.";
|
|
||||||
reasonReturn = "Too many connected users.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// either we aren't restricting users, or this user is in the allowed list
|
||||||
|
|
||||||
|
// if this user is in the editors list, exempt them from the max-capacity check
|
||||||
|
const QVariant* allowedEditorsVariant =
|
||||||
|
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
|
||||||
|
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
|
||||||
|
if (allowedEditors.contains(username)) {
|
||||||
|
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we haven't reached max-capacity, let them in.
|
||||||
|
const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
|
||||||
|
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
|
||||||
|
if (maximumUserCapacity > 0) {
|
||||||
|
unsigned int connectedUsers = countConnectedUsers();
|
||||||
|
if (connectedUsers >= maximumUserCapacity) {
|
||||||
|
// too many users, deny the new connection.
|
||||||
|
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection.";
|
||||||
|
reasonReturn = "Too many connected users.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::preloadAllowedUserPublicKeys() {
|
void DomainServer::preloadAllowedUserPublicKeys() {
|
||||||
|
@ -1255,10 +1256,8 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
|
||||||
// add a flag to indicate if this domain uses restricted access - for now that will exclude it from listings
|
// add a flag to indicate if this domain uses restricted access - for now that will exclude it from listings
|
||||||
const QString RESTRICTED_ACCESS_FLAG = "restricted";
|
const QString RESTRICTED_ACCESS_FLAG = "restricted";
|
||||||
|
|
||||||
const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(),
|
domainObject[RESTRICTED_ACCESS_FLAG] =
|
||||||
ALLOWED_USERS_SETTINGS_KEYPATH);
|
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
||||||
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
|
|
||||||
domainObject[RESTRICTED_ACCESS_FLAG] = (allowedUsers.size() > 0);
|
|
||||||
|
|
||||||
// add the number of currently connected agent users
|
// add the number of currently connected agent users
|
||||||
int numConnectedAuthedUsers = 0;
|
int numConnectedAuthedUsers = 0;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QtCore/QJsonArray>
|
#include <QtCore/QJsonArray>
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
|
#include <QtCore/QSettings>
|
||||||
#include <QtCore/QStandardPaths>
|
#include <QtCore/QStandardPaths>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
#include <QtCore/QUrlQuery>
|
#include <QtCore/QUrlQuery>
|
||||||
|
@ -42,33 +43,73 @@ DomainServerSettingsManager::DomainServerSettingsManager() :
|
||||||
QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH);
|
QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH);
|
||||||
descriptionFile.open(QIODevice::ReadOnly);
|
descriptionFile.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
_descriptionArray = QJsonDocument::fromJson(descriptionFile.readAll()).array();
|
QJsonDocument descriptionDocument = QJsonDocument::fromJson(descriptionFile.readAll());
|
||||||
|
|
||||||
|
if (descriptionDocument.isObject()) {
|
||||||
|
QJsonObject descriptionObject = descriptionDocument.object();
|
||||||
|
|
||||||
|
const QString DESCRIPTION_VERSION_KEY = "version";
|
||||||
|
|
||||||
|
if (descriptionObject.contains(DESCRIPTION_VERSION_KEY)) {
|
||||||
|
// read the version from the settings description
|
||||||
|
_descriptionVersion = descriptionObject[DESCRIPTION_VERSION_KEY].toDouble();
|
||||||
|
|
||||||
|
if (descriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
|
||||||
|
_descriptionArray = descriptionDocument.object()[DESCRIPTION_SETTINGS_KEY].toArray();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qCritical() << "Did not find settings decription in JSON at" << SETTINGS_DESCRIPTION_RELATIVE_PATH
|
||||||
|
<< "- Unable to continue. domain-server will quit.";
|
||||||
|
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) {
|
void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) {
|
||||||
_configMap.loadMasterAndUserConfig(argumentList);
|
_configMap.loadMasterAndUserConfig(argumentList);
|
||||||
|
|
||||||
// for now we perform a temporary transition from http-username and http-password to http_username and http_password
|
// What settings version were we before and what are we using now?
|
||||||
const QVariant* oldUsername = valueForKeyPath(_configMap.getUserConfig(), "security.http-username");
|
// Do we need to do any re-mapping?
|
||||||
const QVariant* oldPassword = valueForKeyPath(_configMap.getUserConfig(), "security.http-password");
|
QSettings appSettings;
|
||||||
|
const QString JSON_SETTINGS_VERSION_KEY = "json-settings/version";
|
||||||
|
double oldVersion = appSettings.value(JSON_SETTINGS_VERSION_KEY, 0.0).toDouble();
|
||||||
|
|
||||||
if (oldUsername || oldPassword) {
|
if (oldVersion != _descriptionVersion) {
|
||||||
QVariantMap& settingsMap = *reinterpret_cast<QVariantMap*>(_configMap.getUserConfig()["security"].data());
|
qDebug() << "Previous domain-server settings version was"
|
||||||
|
<< QString::number(oldVersion, 'g', 8) << "and the new version is"
|
||||||
|
<< QString::number(_descriptionVersion, 'g', 8) << "- checking if any re-mapping is required";
|
||||||
|
|
||||||
// remove old keys, move to new format
|
// we have a version mismatch - for now handle custom behaviour here since there are not many remappings
|
||||||
if (oldUsername) {
|
if (oldVersion < 1.0) {
|
||||||
settingsMap["http_username"] = oldUsername->toString();
|
// This was prior to the introduction of security.restricted_access
|
||||||
settingsMap.remove("http-username");
|
// If the user has a list of allowed users then set their value for security.restricted_access to true
|
||||||
|
|
||||||
|
QVariant* allowedUsers = valueForKeyPath(_configMap.getMergedConfig(), ALLOWED_USERS_SETTINGS_KEYPATH);
|
||||||
|
|
||||||
|
if (allowedUsers
|
||||||
|
&& allowedUsers->canConvert(QMetaType::QVariantList)
|
||||||
|
&& reinterpret_cast<QVariantList*>(allowedUsers)->size() > 0) {
|
||||||
|
|
||||||
|
qDebug() << "Forcing security.restricted_access to TRUE since there was an"
|
||||||
|
<< "existing list of allowed users.";
|
||||||
|
|
||||||
|
// In the pre-toggle system the user had a list of allowed users, so
|
||||||
|
// we need to set security.restricted_access to true
|
||||||
|
QVariant* restrictedAccess = valueForKeyPath(_configMap.getUserConfig(),
|
||||||
|
RESTRICTED_ACCESS_SETTINGS_KEYPATH,
|
||||||
|
true);
|
||||||
|
|
||||||
|
*restrictedAccess = QVariant(true);
|
||||||
|
|
||||||
|
// write the new settings to the json file
|
||||||
|
persistToFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldPassword) {
|
|
||||||
settingsMap["http_password"] = oldPassword->toString();
|
|
||||||
settingsMap.remove("http-password");
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the updated settings
|
|
||||||
persistToFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write the current description version to our settings
|
||||||
|
appSettings.setValue(JSON_SETTINGS_VERSION_KEY, _descriptionVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString &keyPath) {
|
QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString &keyPath) {
|
||||||
|
|
|
@ -23,6 +23,9 @@ const QString SETTINGS_PATHS_KEY = "paths";
|
||||||
const QString SETTINGS_PATH = "/settings";
|
const QString SETTINGS_PATH = "/settings";
|
||||||
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
||||||
|
|
||||||
|
const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users";
|
||||||
|
const QString RESTRICTED_ACCESS_SETTINGS_KEYPATH = "security.restricted_access";
|
||||||
|
|
||||||
class DomainServerSettingsManager : public QObject {
|
class DomainServerSettingsManager : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -44,6 +47,7 @@ private:
|
||||||
QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName);
|
QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName);
|
||||||
void persistToFile();
|
void persistToFile();
|
||||||
|
|
||||||
|
double _descriptionVersion;
|
||||||
QJsonArray _descriptionArray;
|
QJsonArray _descriptionArray;
|
||||||
HifiConfigVariantMap _configMap;
|
HifiConfigVariantMap _configMap;
|
||||||
};
|
};
|
||||||
|
|
|
@ -198,7 +198,7 @@ function checkControllerSide(hand) {
|
||||||
var closestEntity = Entities.findClosestEntity(hand.palmPosition(), CATCH_RADIUS);
|
var closestEntity = Entities.findClosestEntity(hand.palmPosition(), CATCH_RADIUS);
|
||||||
var modelUrl = Entities.getEntityProperties(closestEntity).modelURL;
|
var modelUrl = Entities.getEntityProperties(closestEntity).modelURL;
|
||||||
print("lol2"+closestEntity.isKnownID);
|
print("lol2"+closestEntity.isKnownID);
|
||||||
if (closestEntity.isKnownID && validFrisbeeURL(Entities.getEntityProperties(closestEntity).modelURL)) {
|
if (closestEntity && validFrisbeeURL(Entities.getEntityProperties(closestEntity).modelURL)) {
|
||||||
print("lol");
|
print("lol");
|
||||||
Entities.editEntity(closestEntity, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true});
|
Entities.editEntity(closestEntity, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true});
|
||||||
Entities.deleteEntity(closestEntity);
|
Entities.deleteEntity(closestEntity);
|
||||||
|
@ -448,4 +448,4 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||||
Menu.menuItemEvent.connect(menuItemEvent);
|
Menu.menuItemEvent.connect(menuItemEvent);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
Script.update.connect(checkController);
|
Script.update.connect(checkController);
|
||||||
Script.update.connect(controlFrisbees);
|
Script.update.connect(controlFrisbees);
|
||||||
|
|
|
@ -386,13 +386,6 @@ MyAvatar.attach(gunModel, "LeftHand", {x:-0.04, y: 0.22, z: 0.02}, Quat.fromPitc
|
||||||
Script.setTimeout(playLoadSound, 2000);
|
Script.setTimeout(playLoadSound, 2000);
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
if (bulletID && !bulletID.isKnownID) {
|
|
||||||
bulletID = Entities.identifyEntity(bulletID);
|
|
||||||
}
|
|
||||||
if (targetID && !targetID.isKnownID) {
|
|
||||||
targetID = Entities.identifyEntity(targetID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeControllers == 0) {
|
if (activeControllers == 0) {
|
||||||
if (Controller.getNumberOfSpatialControls() > 0) {
|
if (Controller.getNumberOfSpatialControls() > 0) {
|
||||||
activeControllers = Controller.getNumberOfSpatialControls();
|
activeControllers = Controller.getNumberOfSpatialControls();
|
||||||
|
|
|
@ -132,12 +132,6 @@ function update(deltaTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!paddle.isKnownID) {
|
|
||||||
paddle = Entities.identifyEntity(paddle);
|
|
||||||
}
|
|
||||||
if (!ball.isKnownID) {
|
|
||||||
ball = Entities.identifyEntity(ball);
|
|
||||||
} else {
|
|
||||||
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||||
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
|
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
|
||||||
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
|
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
|
||||||
|
@ -157,7 +151,7 @@ function update(deltaTime) {
|
||||||
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
|
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
|
||||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||||
rotation: paddleWorldOrientation });
|
rotation: paddleWorldOrientation });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||||
|
|
|
@ -109,17 +109,10 @@ function checkControllerSide(whichSide) {
|
||||||
var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5));
|
var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5));
|
||||||
|
|
||||||
// If I don't currently have a ball in my hand, then try to catch closest one
|
// If I don't currently have a ball in my hand, then try to catch closest one
|
||||||
if (leftHandEntity && !leftHandEntity.isKnownID) {
|
|
||||||
leftHandEntity = Entities.identifyEntity(leftHandEntity);
|
|
||||||
}
|
|
||||||
if (rightHandEntity && !rightHandEntity.isKnownID) {
|
|
||||||
rightHandEntity = Entities.identifyEntity(rightHandEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ballAlreadyInHand && grabButtonPressed) {
|
if (!ballAlreadyInHand && grabButtonPressed) {
|
||||||
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
|
var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius);
|
||||||
|
|
||||||
if (closestEntity.isKnownID) {
|
if (closestEntity) {
|
||||||
var foundProperties = Entities.getEntityProperties(closestEntity);
|
var foundProperties = Entities.getEntityProperties(closestEntity);
|
||||||
if (Vec3.length(foundProperties.velocity) > 0.0) {
|
if (Vec3.length(foundProperties.velocity) > 0.0) {
|
||||||
|
|
||||||
|
|
|
@ -579,16 +579,6 @@ function findClickedEntity(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var foundEntity = result.entityID;
|
var foundEntity = result.entityID;
|
||||||
|
|
||||||
if (!foundEntity.isKnownID) {
|
|
||||||
var identify = Entities.identifyEntity(foundEntity);
|
|
||||||
if (!identify.isKnownID) {
|
|
||||||
print("Unknown ID " + identify.id + " (update loop " + foundEntity.id + ")");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
foundEntity = identify;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { pickRay: pickRay, entityID: foundEntity };
|
return { pickRay: pickRay, entityID: foundEntity };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,7 +600,7 @@ function mousePressEvent(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var highlightedEntityID = { isKnownID: false };
|
var highlightedEntityID = null;
|
||||||
var mouseCapturedByTool = false;
|
var mouseCapturedByTool = false;
|
||||||
var lastMousePosition = null;
|
var lastMousePosition = null;
|
||||||
var idleMouseTimerId = null;
|
var idleMouseTimerId = null;
|
||||||
|
@ -625,9 +615,6 @@ function mouseMove(event) {
|
||||||
mouseHasMovedSincePress = true;
|
mouseHasMovedSincePress = true;
|
||||||
|
|
||||||
if (placingEntityID) {
|
if (placingEntityID) {
|
||||||
if (!placingEntityID.isKnownID) {
|
|
||||||
placingEntityID = Entities.identifyEntity(placingEntityID);
|
|
||||||
}
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE;
|
var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE;
|
||||||
var offset = Vec3.multiply(distance, pickRay.direction);
|
var offset = Vec3.multiply(distance, pickRay.direction);
|
||||||
|
@ -664,9 +651,9 @@ function highlightEntityUnderCursor(position, accurateRay) {
|
||||||
var pickRay = Camera.computePickRay(position.x, position.y);
|
var pickRay = Camera.computePickRay(position.x, position.y);
|
||||||
var entityIntersection = Entities.findRayIntersection(pickRay, accurateRay);
|
var entityIntersection = Entities.findRayIntersection(pickRay, accurateRay);
|
||||||
if (entityIntersection.accurate) {
|
if (entityIntersection.accurate) {
|
||||||
if(highlightedEntityID.isKnownID && highlightedEntityID.id != entityIntersection.entityID.id) {
|
if(highlightedEntityID && highlightedEntityID != entityIntersection.entityID) {
|
||||||
selectionDisplay.unhighlightSelectable(highlightedEntityID);
|
selectionDisplay.unhighlightSelectable(highlightedEntityID);
|
||||||
highlightedEntityID = { id: -1, isKnownID: false };
|
highlightedEntityID = { id: -1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
|
var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0;
|
||||||
|
@ -677,7 +664,7 @@ function highlightEntityUnderCursor(position, accurateRay) {
|
||||||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE)
|
||||||
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
&& (allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||||
|
|
||||||
if (entityIntersection.entityID.isKnownID && sizeOK) {
|
if (entityIntersection.entityID && sizeOK) {
|
||||||
if (wantEntityGlow) {
|
if (wantEntityGlow) {
|
||||||
Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 });
|
Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 });
|
||||||
}
|
}
|
||||||
|
@ -736,7 +723,7 @@ function mouseClickEvent(event) {
|
||||||
} else {
|
} else {
|
||||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||||
|
|
||||||
print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal);
|
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
|
||||||
// P P - Model
|
// P P - Model
|
||||||
// /| A - Palm
|
// /| A - Palm
|
||||||
// / | d B - unit vector toward tip
|
// / | d B - unit vector toward tip
|
||||||
|
@ -967,8 +954,8 @@ function deleteSelectedEntities() {
|
||||||
var savedProperties = [];
|
var savedProperties = [];
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
var entityID = SelectionManager.selections[i];
|
var entityID = SelectionManager.selections[i];
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||||
SelectionManager.savedProperties[entityID.id];
|
SelectionManager.savedProperties[entityID];
|
||||||
savedProperties.push({
|
savedProperties.push({
|
||||||
entityID: entityID,
|
entityID: entityID,
|
||||||
properties: initialProperties
|
properties: initialProperties
|
||||||
|
@ -1127,8 +1114,8 @@ function applyEntityProperties(data) {
|
||||||
var selectedEntityIDs = [];
|
var selectedEntityIDs = [];
|
||||||
for (var i = 0; i < properties.length; i++) {
|
for (var i = 0; i < properties.length; i++) {
|
||||||
var entityID = properties[i].entityID;
|
var entityID = properties[i].entityID;
|
||||||
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
|
if (DELETED_ENTITY_MAP[entityID] !== undefined) {
|
||||||
entityID = DELETED_ENTITY_MAP[entityID.id];
|
entityID = DELETED_ENTITY_MAP[entityID];
|
||||||
}
|
}
|
||||||
Entities.editEntity(entityID, properties[i].properties);
|
Entities.editEntity(entityID, properties[i].properties);
|
||||||
selectedEntityIDs.push(entityID);
|
selectedEntityIDs.push(entityID);
|
||||||
|
@ -1137,15 +1124,15 @@ function applyEntityProperties(data) {
|
||||||
var entityID = data.createEntities[i].entityID;
|
var entityID = data.createEntities[i].entityID;
|
||||||
var properties = data.createEntities[i].properties;
|
var properties = data.createEntities[i].properties;
|
||||||
var newEntityID = Entities.addEntity(properties);
|
var newEntityID = Entities.addEntity(properties);
|
||||||
DELETED_ENTITY_MAP[entityID.id] = newEntityID;
|
DELETED_ENTITY_MAP[entityID] = newEntityID;
|
||||||
if (data.selectCreated) {
|
if (data.selectCreated) {
|
||||||
selectedEntityIDs.push(newEntityID);
|
selectedEntityIDs.push(newEntityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var i = 0; i < data.deleteEntities.length; i++) {
|
for (var i = 0; i < data.deleteEntities.length; i++) {
|
||||||
var entityID = data.deleteEntities[i].entityID;
|
var entityID = data.deleteEntities[i].entityID;
|
||||||
if (DELETED_ENTITY_MAP[entityID.id] !== undefined) {
|
if (DELETED_ENTITY_MAP[entityID] !== undefined) {
|
||||||
entityID = DELETED_ENTITY_MAP[entityID.id];
|
entityID = DELETED_ENTITY_MAP[entityID];
|
||||||
}
|
}
|
||||||
Entities.deleteEntity(entityID);
|
Entities.deleteEntity(entityID);
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1157,7 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
|
||||||
};
|
};
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var entityID = SelectionManager.selections[i];
|
var entityID = SelectionManager.selections[i];
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||||
var currentProperties = Entities.getEntityProperties(entityID);
|
var currentProperties = Entities.getEntityProperties(entityID);
|
||||||
undoData.setProperties.push({
|
undoData.setProperties.push({
|
||||||
entityID: entityID,
|
entityID: entityID,
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
// All callbacks start by updating the properties
|
// All callbacks start by updating the properties
|
||||||
this.updateProperties = function(entityID) {
|
this.updateProperties = function(entityID) {
|
||||||
// Piece ID
|
// Piece ID
|
||||||
if (this.entityID === null || !this.entityID.isKnownID) {
|
if (this.entityID === null) {
|
||||||
this.entityID = Entities.identifyEntity(entityID);
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
// Piece Properties
|
// Piece Properties
|
||||||
this.properties = Entities.getEntityProperties(this.entityID);
|
this.properties = Entities.getEntityProperties(this.entityID);
|
||||||
|
@ -27,12 +27,7 @@
|
||||||
if (this.boardID === null) {
|
if (this.boardID === null) {
|
||||||
// Read user data string and update boardID
|
// Read user data string and update boardID
|
||||||
var userData = JSON.parse(this.properties.userData);
|
var userData = JSON.parse(this.properties.userData);
|
||||||
var boardID = Entities.identifyEntity(userData.boardID);
|
this.boardID = userData.boardID;
|
||||||
if (boardID.isKnownID) {
|
|
||||||
this.boardID = boardID;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Board User Data
|
// Board User Data
|
||||||
|
@ -52,13 +47,13 @@
|
||||||
// Updates user data related objects
|
// Updates user data related objects
|
||||||
this.updateUserData = function() {
|
this.updateUserData = function() {
|
||||||
// Get board's user data
|
// Get board's user data
|
||||||
if (this.boardID !== null && this.boardID.isKnownID) {
|
if (this.boardID !== null) {
|
||||||
this.boardUserData = this.getEntityUserData(this.boardID);
|
this.boardUserData = this.getEntityUserData(this.boardID);
|
||||||
|
|
||||||
if (!(this.boardUserData &&
|
if (!(this.boardUserData &&
|
||||||
this.boardUserData.firstTile &&
|
this.boardUserData.firstTile &&
|
||||||
this.boardUserData.tileSize)) {
|
this.boardUserData.tileSize)) {
|
||||||
print("Incomplete boardUserData " + this.boardID.id);
|
print("Incomplete boardUserData " + this.boardID);
|
||||||
} else {
|
} else {
|
||||||
this.FIRST_TILE = this.boardUserData.firstTile;
|
this.FIRST_TILE = this.boardUserData.firstTile;
|
||||||
this.TILE_SIZE = this.boardUserData.tileSize;
|
this.TILE_SIZE = this.boardUserData.tileSize;
|
||||||
|
@ -137,7 +132,7 @@
|
||||||
for (var i = 0; i < others.length; i++) {
|
for (var i = 0; i < others.length; i++) {
|
||||||
var piece = others[i];
|
var piece = others[i];
|
||||||
|
|
||||||
if (piece.id != this.entityID.id) {
|
if (piece.id != this.entityID) {
|
||||||
var properties = Entities.getEntityProperties(piece);
|
var properties = Entities.getEntityProperties(piece);
|
||||||
|
|
||||||
var isWhite = properties.modelURL.search("White") !== -1;
|
var isWhite = properties.modelURL.search("White") !== -1;
|
||||||
|
@ -198,4 +193,4 @@
|
||||||
this.updateProperties(entityID); // All callbacks start by updating the properties
|
this.updateProperties(entityID); // All callbacks start by updating the properties
|
||||||
this.release(mouseEvent);
|
this.release(mouseEvent);
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
}
|
}
|
||||||
// All callbacks start by updating the properties
|
// All callbacks start by updating the properties
|
||||||
this.updateProperties = function(entityID) {
|
this.updateProperties = function(entityID) {
|
||||||
if (this.entityID === null || !this.entityID.isKnownID) {
|
if (this.entityID === null) {
|
||||||
this.entityID = Entities.identifyEntity(entityID);
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
this.properties = Entities.getEntityProperties(this.entityID);
|
this.properties = Entities.getEntityProperties(this.entityID);
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,14 +32,14 @@
|
||||||
return JSON.parse(JSON.stringify(object));
|
return JSON.parse(JSON.stringify(object));
|
||||||
}
|
}
|
||||||
function didEntityExist(entityID) {
|
function didEntityExist(entityID) {
|
||||||
return entityID && entityID.isKnownID;
|
return entityID;
|
||||||
}
|
}
|
||||||
function doesEntityExistNow(entityID) {
|
function doesEntityExistNow(entityID) {
|
||||||
return entityID && getTrueID(entityID).isKnownID;
|
return entityID;
|
||||||
}
|
}
|
||||||
function getTrueID(entityID) {
|
function getTrueID(entityID) {
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
return { id: properties.id, creatorTokenID: properties.creatorTokenID, isKnownID: properties.isKnownID };
|
return { id: properties.id };
|
||||||
}
|
}
|
||||||
function getUserData(entityID) {
|
function getUserData(entityID) {
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
|
@ -225,4 +225,4 @@
|
||||||
this.updateRelativeLightPosition();
|
this.updateRelativeLightPosition();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -251,8 +251,8 @@
|
||||||
};
|
};
|
||||||
// All callbacks start by updating the properties
|
// All callbacks start by updating the properties
|
||||||
this.updateProperties = function(entityID) {
|
this.updateProperties = function(entityID) {
|
||||||
if (this.entityID === null || !this.entityID.isKnownID) {
|
if (this.entityID === null) {
|
||||||
this.entityID = Entities.identifyEntity(entityID);
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
this.properties = Entities.getEntityProperties(this.entityID);
|
this.properties = Entities.getEntityProperties(this.entityID);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
var bird;
|
var bird;
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
print("preload("+entityID.id+")");
|
print("preload("+entityID+")");
|
||||||
bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
|
bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
print("preload("+entityID.id+")");
|
print("preload("+entityID+")");
|
||||||
bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
|
bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw");
|
||||||
};
|
};
|
||||||
|
|
||||||
this.enterEntity = function(entityID) {
|
this.enterEntity = function(entityID) {
|
||||||
print("enterEntity("+entityID.id+")");
|
print("enterEntity("+entityID+")");
|
||||||
playSound();
|
playSound();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.leaveEntity = function(entityID) {
|
this.leaveEntity = function(entityID) {
|
||||||
print("leaveEntity("+entityID.id+")");
|
print("leaveEntity("+entityID+")");
|
||||||
playSound();
|
playSound();
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -312,7 +312,7 @@
|
||||||
this.indicator[i].position,
|
this.indicator[i].position,
|
||||||
this.indicator[i].scale / 2)) {
|
this.indicator[i].scale / 2)) {
|
||||||
clickedOnSeat = true;
|
clickedOnSeat = true;
|
||||||
seat.model = this.entityID; // ??
|
seat.model = this.entityID;
|
||||||
seat.position = this.indicator[i].position;
|
seat.position = this.indicator[i].position;
|
||||||
seat.rotation = this.indicator[i].orientation;
|
seat.rotation = this.indicator[i].orientation;
|
||||||
}
|
}
|
||||||
|
@ -333,8 +333,8 @@
|
||||||
|
|
||||||
// All callbacks start by updating the properties
|
// All callbacks start by updating the properties
|
||||||
this.updateProperties = function(entityID) {
|
this.updateProperties = function(entityID) {
|
||||||
if (this.entityID === null || !this.entityID.isKnownID) {
|
if (this.entityID === null) {
|
||||||
this.entityID = Entities.identifyEntity(entityID);
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
this.properties = Entities.getEntityProperties(this.entityID);
|
this.properties = Entities.getEntityProperties(this.entityID);
|
||||||
};
|
};
|
||||||
|
@ -369,4 +369,4 @@
|
||||||
this.updateProperties(entityID); // All callbacks start by updating the properties
|
this.updateProperties(entityID); // All callbacks start by updating the properties
|
||||||
};
|
};
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -42,7 +42,6 @@ var originalProperties = {
|
||||||
};
|
};
|
||||||
|
|
||||||
var modelID = Entities.addEntity(originalProperties);
|
var modelID = Entities.addEntity(originalProperties);
|
||||||
print("Entities.addEntity()... modelID.creatorTokenID = " + modelID.creatorTokenID);
|
|
||||||
|
|
||||||
var isPlaying = true;
|
var isPlaying = true;
|
||||||
var playPauseEveryWhile = 360;
|
var playPauseEveryWhile = 360;
|
||||||
|
@ -98,8 +97,6 @@ function moveModel(deltaTime) {
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
//print("modelID.creatorTokenID = " + modelID.creatorTokenID);
|
|
||||||
|
|
||||||
if (somethingChanged) {
|
if (somethingChanged) {
|
||||||
var newProperties = {
|
var newProperties = {
|
||||||
animationIsPlaying: isPlaying,
|
animationIsPlaying: isPlaying,
|
||||||
|
@ -123,7 +120,7 @@ Script.update.connect(moveModel);
|
||||||
|
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
print("cleaning up...");
|
print("cleaning up...");
|
||||||
print("modelID="+ modelID.creatorTokenID + ", id:" + modelID.id);
|
print("modelID=" + modelID);
|
||||||
Models.deleteModel(modelID);
|
Models.deleteModel(modelID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -106,9 +106,6 @@ function updateButterflies(deltaTime) {
|
||||||
var CHANCE_OF_IMPULSE = 0.04;
|
var CHANCE_OF_IMPULSE = 0.04;
|
||||||
for (var i = 0; i < numButterflies; i++) {
|
for (var i = 0; i < numButterflies; i++) {
|
||||||
if (Math.random() < CHANCE_OF_IMPULSE) {
|
if (Math.random() < CHANCE_OF_IMPULSE) {
|
||||||
if (!butterflies[i].isKnownID) {
|
|
||||||
butterflies[i] = Entities.identifyEntity(butterflies[i]);
|
|
||||||
}
|
|
||||||
var properties = Entities.getEntityProperties(butterflies[i]);
|
var properties = Entities.getEntityProperties(butterflies[i]);
|
||||||
if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) {
|
if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) {
|
||||||
Entities.editEntity(butterflies[i], { position: flockPosition } );
|
Entities.editEntity(butterflies[i], { position: flockPosition } );
|
||||||
|
|
|
@ -71,8 +71,6 @@ function moveEntity(deltaTime) {
|
||||||
print("count =" + count);
|
print("count =" + count);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
|
||||||
|
|
||||||
var newProperties = {
|
var newProperties = {
|
||||||
position: {
|
position: {
|
||||||
x: originalProperties.position.x + (count * positionDelta.x),
|
x: originalProperties.position.x + (count * positionDelta.x),
|
||||||
|
|
|
@ -70,8 +70,6 @@ function moveEntity(deltaTime) {
|
||||||
print("count =" + count);
|
print("count =" + count);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
|
||||||
|
|
||||||
var newProperties = {
|
var newProperties = {
|
||||||
position: {
|
position: {
|
||||||
x: originalProperties.position.x + (count * positionDelta.x),
|
x: originalProperties.position.x + (count * positionDelta.x),
|
||||||
|
|
|
@ -38,10 +38,6 @@ var moveSearch = { x: 0.1, y: 0, z: 0.1};
|
||||||
var searchRadius = 1;
|
var searchRadius = 1;
|
||||||
var searchRadiusChange = 0;
|
var searchRadiusChange = 0;
|
||||||
|
|
||||||
print("entityA.creatorTokenID = " + entityA.creatorTokenID);
|
|
||||||
print("entityB.creatorTokenID = " + entityB.creatorTokenID);
|
|
||||||
|
|
||||||
|
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
print("calling Entities.deleteEntity()");
|
print("calling Entities.deleteEntity()");
|
||||||
Entities.deleteEntity(entityA);
|
Entities.deleteEntity(entityA);
|
||||||
|
@ -77,22 +73,6 @@ function findEntities(deltaTime) {
|
||||||
print("--------------------------");
|
print("--------------------------");
|
||||||
print("iteration =" + iteration);
|
print("iteration =" + iteration);
|
||||||
iteration++;
|
iteration++;
|
||||||
|
|
||||||
// Check to see if we've been notified of the actual identity of the entities we created
|
|
||||||
if (!entityA.isKnownID) {
|
|
||||||
var identifyA = Entities.identifyEntity(entityA);
|
|
||||||
if (identifyA.isKnownID) {
|
|
||||||
entityA = identifyA;
|
|
||||||
print(">>>> identified entityA.id = " + entityA.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!entityB.isKnownID) {
|
|
||||||
var identifyB = Entities.identifyEntity(entityB);
|
|
||||||
if (identifyB.isKnownID) {
|
|
||||||
entityB = identifyB;
|
|
||||||
print(">>>> identified entityB.id = " + entityB.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// also check to see if we can "find" entities...
|
// also check to see if we can "find" entities...
|
||||||
print("searching for entities at:" + searchAt.x + ", " + searchAt.y + ", " + searchAt.z + " radius:" + searchRadius);
|
print("searching for entities at:" + searchAt.x + ", " + searchAt.y + ", " + searchAt.z + " radius:" + searchRadius);
|
||||||
|
|
|
@ -177,18 +177,11 @@ function updateBirds(deltaTime) {
|
||||||
var averagePosition = { x: 0, y: 0, z: 0};
|
var averagePosition = { x: 0, y: 0, z: 0};
|
||||||
var knownBirds = 0;
|
var knownBirds = 0;
|
||||||
for(var i =0; i < birdsInFlock; i++) {
|
for(var i =0; i < birdsInFlock; i++) {
|
||||||
// identifyParticle() will check to see that the particle handle we have is in sync with the domain/server
|
birds[i].properties = Entities.getEntityProperties(birds[i].particle);
|
||||||
// context. If the handle is for a created particle that now has a known ID it will be updated to be a
|
if (birds[i].properties) {
|
||||||
// handle with a known ID.
|
knownBirds++;
|
||||||
birds[i].particle = Entities.identifyEntity(birds[i].particle);
|
averageVelocity = Vec3.sum(averageVelocity, birds[i].properties.velocity);
|
||||||
|
averagePosition = Vec3.sum(averagePosition, birds[i].properties.position);
|
||||||
if (birds[i].particle.isKnownID) {
|
|
||||||
birds[i].properties = Entities.getEntityProperties(birds[i].particle);
|
|
||||||
if (birds[i].properties.isKnownID) {
|
|
||||||
knownBirds++;
|
|
||||||
averageVelocity = Vec3.sum(averageVelocity, birds[i].properties.velocity);
|
|
||||||
averagePosition = Vec3.sum(averagePosition, birds[i].properties.position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +213,7 @@ function updateBirds(deltaTime) {
|
||||||
|
|
||||||
birds[i].thrust = { x: 0, y: 0, z: 0 }; // assume no thrust...
|
birds[i].thrust = { x: 0, y: 0, z: 0 }; // assume no thrust...
|
||||||
|
|
||||||
if (birds[i].particle.isKnownID) {
|
if (birds[i].particle) {
|
||||||
|
|
||||||
if (enableFlyTowardPoints) {
|
if (enableFlyTowardPoints) {
|
||||||
// if we're flying toward clusters, and the cluster changed, and this bird is flyingToward
|
// if we're flying toward clusters, and the cluster changed, and this bird is flyingToward
|
||||||
|
@ -400,7 +393,7 @@ function updateBirds(deltaTime) {
|
||||||
for(var j =0; j < birdsInFlock; j++) {
|
for(var j =0; j < birdsInFlock; j++) {
|
||||||
|
|
||||||
// if this is not me, and a known bird, then check our position
|
// if this is not me, and a known bird, then check our position
|
||||||
if (birds[i].properties.isKnownID && j != i) {
|
if (birds[i].properties && j != i) {
|
||||||
var positionMe = birds[i].properties.position;
|
var positionMe = birds[i].properties.position;
|
||||||
var positionYou = birds[j].properties.position;
|
var positionYou = birds[j].properties.position;
|
||||||
var awayFromYou = Vec3.subtract(positionMe, positionYou); // vector pointing away from "you"
|
var awayFromYou = Vec3.subtract(positionMe, positionYou); // vector pointing away from "you"
|
||||||
|
@ -428,7 +421,7 @@ function updateBirds(deltaTime) {
|
||||||
|
|
||||||
// iterate all birds again, apply their thrust
|
// iterate all birds again, apply their thrust
|
||||||
for(var i =0; i < birdsInFlock; i++) {
|
for(var i =0; i < birdsInFlock; i++) {
|
||||||
if (birds[i].particle.isKnownID) {
|
if (birds[i].particle) {
|
||||||
|
|
||||||
var color;
|
var color;
|
||||||
if (birds[i].gliding) {
|
if (birds[i].gliding) {
|
||||||
|
|
|
@ -29,10 +29,6 @@ function rideWithEntity(deltaTime) {
|
||||||
if (iteration <= lengthOfRide) {
|
if (iteration <= lengthOfRide) {
|
||||||
|
|
||||||
// Check to see if we've been notified of the actual identity of the entities we created
|
// Check to see if we've been notified of the actual identity of the entities we created
|
||||||
if (!entityA.isKnownID) {
|
|
||||||
entityA = Entities.identifyEntity(entityA);
|
|
||||||
}
|
|
||||||
|
|
||||||
var propertiesA = Entities.getEntityProperties(entityA);
|
var propertiesA = Entities.getEntityProperties(entityA);
|
||||||
var newPosition = propertiesA.position;
|
var newPosition = propertiesA.position;
|
||||||
MyAvatar.position = { x: propertiesA.position.x - 1,
|
MyAvatar.position = { x: propertiesA.position.x - 1,
|
||||||
|
|
|
@ -206,15 +206,9 @@ function keyPressEvent(event) {
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
for (var i = 0; i < tableParts.length; i++) {
|
for (var i = 0; i < tableParts.length; i++) {
|
||||||
if (!tableParts[i].isKnownID) {
|
|
||||||
tableParts[i] = Entities.identifyEntity(tableParts[i]);
|
|
||||||
}
|
|
||||||
Entities.deleteEntity(tableParts[i]);
|
Entities.deleteEntity(tableParts[i]);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < balls.length; i++) {
|
for (var i = 0; i < balls.length; i++) {
|
||||||
if (!balls[i].isKnownID) {
|
|
||||||
balls[i] = Entities.identifyEntity(balls[i]);
|
|
||||||
}
|
|
||||||
Entities.deleteEntity(balls[i]);
|
Entities.deleteEntity(balls[i]);
|
||||||
}
|
}
|
||||||
Overlays.deleteOverlay(reticle);
|
Overlays.deleteOverlay(reticle);
|
||||||
|
@ -222,18 +216,13 @@ function cleanup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
if (!cueBall.isKnownID) {
|
// Check if cue ball has fallen off table, re-drop if so
|
||||||
cueBall = Entities.identifyEntity(cueBall);
|
var cueProperties = Entities.getEntityProperties(cueBall);
|
||||||
} else {
|
if (cueProperties.position.y < tableCenter.y) {
|
||||||
// Check if cue ball has fallen off table, re-drop if so
|
// Replace the cueball
|
||||||
var cueProperties = Entities.getEntityProperties(cueBall);
|
Entities.editEntity(cueBall, { position: cuePosition } );
|
||||||
if (cueProperties.position.y < tableCenter.y) {
|
|
||||||
// Replace the cueball
|
|
||||||
Entities.editEntity(cueBall, { position: cuePosition } );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||||
|
|
|
@ -157,7 +157,7 @@ ChessGame.Piece = (function(position, dimensions, url, rotation) {
|
||||||
});
|
});
|
||||||
// Build the user data string
|
// Build the user data string
|
||||||
ChessGame.Piece.prototype.buildUserDataString = function() {
|
ChessGame.Piece.prototype.buildUserDataString = function() {
|
||||||
if (!(ChessGame.board !== null || ChessGame.board.entity.isKnownID)) {
|
if (!ChessGame.board) {
|
||||||
print("ChessGame.Piece.prototype.buildUserDataString(): Called before proper initialization, bailing.");
|
print("ChessGame.Piece.prototype.buildUserDataString(): Called before proper initialization, bailing.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -200,9 +200,7 @@ ChessGame.scriptStarting = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChessGame.update = function() {
|
ChessGame.update = function() {
|
||||||
ChessGame.board.entity = Entities.identifyEntity(ChessGame.board.entity);
|
if (ChessGame.board.entity && ChessGame.pieces.length == 0) {
|
||||||
|
|
||||||
if (ChessGame.board.entity.isKnownID && ChessGame.pieces.length == 0) {
|
|
||||||
// Setup white pieces
|
// Setup white pieces
|
||||||
var isWhite = true;
|
var isWhite = true;
|
||||||
var row = 1;
|
var row = 1;
|
||||||
|
@ -260,4 +258,4 @@ ChessGame.scriptEnding = function() {
|
||||||
|
|
||||||
Script.scriptEnding.connect(ChessGame.scriptEnding);
|
Script.scriptEnding.connect(ChessGame.scriptEnding);
|
||||||
Script.update.connect(ChessGame.update);
|
Script.update.connect(ChessGame.update);
|
||||||
ChessGame.scriptStarting();
|
ChessGame.scriptStarting();
|
||||||
|
|
|
@ -183,8 +183,6 @@ function initializeInvaders() {
|
||||||
modelURL: invaderModels[row].modelURL,
|
modelURL: invaderModels[row].modelURL,
|
||||||
lifetime: itemLifetimes
|
lifetime: itemLifetimes
|
||||||
});
|
});
|
||||||
|
|
||||||
print("invaders[row][column].creatorTokenID=" + invaders[row][column].creatorTokenID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +191,7 @@ function moveInvaders() {
|
||||||
for (var row = 0; row < numberOfRows; row++) {
|
for (var row = 0; row < numberOfRows; row++) {
|
||||||
for (var column = 0; column < invadersPerRow; column++) {
|
for (var column = 0; column < invadersPerRow; column++) {
|
||||||
props = Entities.getEntityProperties(invaders[row][column]);
|
props = Entities.getEntityProperties(invaders[row][column]);
|
||||||
if (props.isKnownID) {
|
if (props.id) {
|
||||||
invaderPosition = getInvaderPosition(row, column);
|
invaderPosition = getInvaderPosition(row, column);
|
||||||
Entities.editEntity(invaders[row][column],
|
Entities.editEntity(invaders[row][column],
|
||||||
{
|
{
|
||||||
|
@ -292,7 +290,6 @@ function endGame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveShipTo(position) {
|
function moveShipTo(position) {
|
||||||
myShip = Entities.identifyEntity(myShip);
|
|
||||||
Entities.editEntity(myShip, { position: position });
|
Entities.editEntity(myShip, { position: position });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,9 +300,8 @@ function fireMissile() {
|
||||||
// If we've fired a missile, then check to see if it's still alive
|
// If we've fired a missile, then check to see if it's still alive
|
||||||
if (missileFired) {
|
if (missileFired) {
|
||||||
var missileProperties = Entities.getEntityProperties(myMissile);
|
var missileProperties = Entities.getEntityProperties(myMissile);
|
||||||
print("missileProperties.isKnownID=" + missileProperties.isKnownID);
|
|
||||||
|
|
||||||
if (!missileProperties.isKnownID) {
|
if (!missileProperties) {
|
||||||
print("canFire = true");
|
print("canFire = true");
|
||||||
canFire = true;
|
canFire = true;
|
||||||
}
|
}
|
||||||
|
@ -374,24 +370,21 @@ Controller.captureKeyEvents({text: " "});
|
||||||
function deleteIfInvader(possibleInvaderEntity) {
|
function deleteIfInvader(possibleInvaderEntity) {
|
||||||
for (var row = 0; row < numberOfRows; row++) {
|
for (var row = 0; row < numberOfRows; row++) {
|
||||||
for (var column = 0; column < invadersPerRow; column++) {
|
for (var column = 0; column < invadersPerRow; column++) {
|
||||||
invaders[row][column] = Entities.identifyEntity(invaders[row][column]);
|
if (invaders[row][column].id && invaders[row][column].id == possibleInvaderEntity.id) {
|
||||||
if (invaders[row][column].isKnownID) {
|
Entities.deleteEntity(possibleInvaderEntity);
|
||||||
if (invaders[row][column].id == possibleInvaderEntity.id) {
|
Entities.deleteEntity(myMissile);
|
||||||
Entities.deleteEntity(possibleInvaderEntity);
|
|
||||||
Entities.deleteEntity(myMissile);
|
|
||||||
|
|
||||||
// play the hit sound
|
// play the hit sound
|
||||||
var options = {};
|
var options = {};
|
||||||
if (soundInMyHead) {
|
if (soundInMyHead) {
|
||||||
options.position = { x: MyAvatar.position.x + 0.0,
|
options.position = { x: MyAvatar.position.x + 0.0,
|
||||||
y: MyAvatar.position.y + 0.1,
|
y: MyAvatar.position.y + 0.1,
|
||||||
z: MyAvatar.position.z + 0.0 };
|
z: MyAvatar.position.z + 0.0 };
|
||||||
} else {
|
} else {
|
||||||
options.position = getInvaderPosition(row, column);
|
options.position = getInvaderPosition(row, column);
|
||||||
}
|
|
||||||
|
|
||||||
Audio.playSound(hitSound, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Audio.playSound(hitSound, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,7 +395,6 @@ function entityCollisionWithEntity(entityA, entityB, collision) {
|
||||||
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
|
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
|
||||||
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
|
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
|
||||||
if (missileFired) {
|
if (missileFired) {
|
||||||
myMissile = Entities.identifyEntity(myMissile);
|
|
||||||
if (myMissile.id == entityA.id) {
|
if (myMissile.id == entityA.id) {
|
||||||
deleteIfInvader(entityB);
|
deleteIfInvader(entityB);
|
||||||
} else if (myMissile.id == entityB.id) {
|
} else if (myMissile.id == entityB.id) {
|
||||||
|
|
|
@ -42,9 +42,6 @@ function randomColor() {
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
time += deltaTime;
|
time += deltaTime;
|
||||||
if (!ball.isKnownID) {
|
|
||||||
ball = Entities.identifyEntity(ball);
|
|
||||||
}
|
|
||||||
rotation = Quat.angleAxis(time * omega /Math.PI * 180.0, { x: 0, y: 1, z: 0 });
|
rotation = Quat.angleAxis(time * omega /Math.PI * 180.0, { x: 0, y: 1, z: 0 });
|
||||||
Entities.editEntity(ball,
|
Entities.editEntity(ball,
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
|
|
||||||
function onRowClicked(e) {
|
function onRowClicked(e) {
|
||||||
var id = this.dataset.entityId;
|
var id = this.dataset.entityId;
|
||||||
|
|
||||||
var selection = [this.dataset.entityId];
|
var selection = [this.dataset.entityId];
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
selection = selection.concat(selectedEntities);
|
selection = selection.concat(selectedEntities);
|
||||||
|
|
|
@ -21,7 +21,7 @@ EntityListTool = function(opts) {
|
||||||
var selectedIDs = [];
|
var selectedIDs = [];
|
||||||
|
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
selectedIDs.push(selectionManager.selections[i].id);
|
selectedIDs.push(selectionManager.selections[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
|
@ -38,7 +38,7 @@ EntityListTool = function(opts) {
|
||||||
var id = ids[i];
|
var id = ids[i];
|
||||||
var properties = Entities.getEntityProperties(id);
|
var properties = Entities.getEntityProperties(id);
|
||||||
entities.push({
|
entities.push({
|
||||||
id: id.id,
|
id: id,
|
||||||
name: properties.name,
|
name: properties.name,
|
||||||
type: properties.type,
|
type: properties.type,
|
||||||
url: properties.type == "Model" ? properties.modelURL : "",
|
url: properties.type == "Model" ? properties.modelURL : "",
|
||||||
|
@ -47,7 +47,7 @@ EntityListTool = function(opts) {
|
||||||
|
|
||||||
var selectedIDs = [];
|
var selectedIDs = [];
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
selectedIDs.push(selectionManager.selections[i].id);
|
selectedIDs.push(selectionManager.selections[i].id); // ?
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
|
@ -64,11 +64,7 @@ EntityListTool = function(opts) {
|
||||||
var ids = data.entityIds;
|
var ids = data.entityIds;
|
||||||
var entityIDs = [];
|
var entityIDs = [];
|
||||||
for (var i = 0; i < ids.length; i++) {
|
for (var i = 0; i < ids.length; i++) {
|
||||||
entityIDs.push({
|
entityIDs.push(ids[i]);
|
||||||
id: ids[i],
|
|
||||||
isKnownID: true,
|
|
||||||
creatorTokenID: 0,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
selectionManager.setSelections(entityIDs);
|
selectionManager.setSelections(entityIDs);
|
||||||
if (data.focus) {
|
if (data.focus) {
|
||||||
|
|
|
@ -19,15 +19,8 @@ SPACE_WORLD = "world";
|
||||||
SelectionManager = (function() {
|
SelectionManager = (function() {
|
||||||
var that = {};
|
var that = {};
|
||||||
|
|
||||||
var PENDING_SELECTION_CHECK_INTERVAL = 50;
|
|
||||||
|
|
||||||
that.savedProperties = {};
|
that.savedProperties = {};
|
||||||
|
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
// These are selections that don't have a known ID yet
|
|
||||||
that.pendingSelections = [];
|
|
||||||
var pendingSelectionTimer = null;
|
|
||||||
|
|
||||||
var listeners = [];
|
var listeners = [];
|
||||||
|
|
||||||
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||||
|
@ -45,7 +38,7 @@ SelectionManager = (function() {
|
||||||
that.savedProperties = {};
|
that.savedProperties = {};
|
||||||
for (var i = 0; i < that.selections.length; i++) {
|
for (var i = 0; i < that.selections.length; i++) {
|
||||||
var entityID = that.selections[i];
|
var entityID = that.selections[i];
|
||||||
that.savedProperties[entityID.id] = Entities.getEntityProperties(entityID);
|
that.savedProperties[entityID] = Entities.getEntityProperties(entityID);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,41 +54,17 @@ SelectionManager = (function() {
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
for (var i = 0; i < entityIDs.length; i++) {
|
for (var i = 0; i < entityIDs.length; i++) {
|
||||||
var entityID = entityIDs[i];
|
var entityID = entityIDs[i];
|
||||||
if (entityID.isKnownID) {
|
that.selections.push(entityID);
|
||||||
that.selections.push(entityID);
|
|
||||||
} else {
|
|
||||||
that.pendingSelections.push(entityID);
|
|
||||||
if (pendingSelectionTimer == null) {
|
|
||||||
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
};
|
};
|
||||||
|
|
||||||
that._checkPendingSelections = function() {
|
|
||||||
for (var i = 0; i < that.pendingSelections.length; i++) {
|
|
||||||
var entityID = that.pendingSelections[i];
|
|
||||||
var newEntityID = Entities.identifyEntity(entityID);
|
|
||||||
if (newEntityID.isKnownID) {
|
|
||||||
that.pendingSelections.splice(i, 1);
|
|
||||||
that.addEntity(newEntityID);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (that.pendingSelections.length == 0) {
|
|
||||||
Script.clearInterval(pendingSelectionTimer);
|
|
||||||
pendingSelectionTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
that.addEntity = function(entityID, toggleSelection) {
|
that.addEntity = function(entityID, toggleSelection) {
|
||||||
if (entityID.isKnownID) {
|
if (entityID) {
|
||||||
var idx = -1;
|
var idx = -1;
|
||||||
for (var i = 0; i < that.selections.length; i++) {
|
for (var i = 0; i < that.selections.length; i++) {
|
||||||
if (entityID.id == that.selections[i].id) {
|
if (entityID == that.selections[i]) {
|
||||||
idx = i;
|
idx = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -105,14 +74,6 @@ SelectionManager = (function() {
|
||||||
} else if (toggleSelection) {
|
} else if (toggleSelection) {
|
||||||
that.selections.splice(idx, 1);
|
that.selections.splice(idx, 1);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
var idx = that.pendingSelections.indexOf(entityID);
|
|
||||||
if (idx == -1) {
|
|
||||||
that.pendingSelections.push(entityID);
|
|
||||||
if (pendingSelectionTimer == null) {
|
|
||||||
pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
|
@ -123,24 +84,11 @@ SelectionManager = (function() {
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
that.selections.splice(idx, 1);
|
that.selections.splice(idx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var idx = that.pendingSelections.indexOf(entityID);
|
|
||||||
if (idx >= 0) {
|
|
||||||
that.pendingSelections.splice(idx, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
};
|
};
|
||||||
|
|
||||||
that.clearSelections = function() {
|
that.clearSelections = function() {
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
that.pendingSelections = [];
|
|
||||||
|
|
||||||
if (pendingSelectionTimer !== null) {
|
|
||||||
Script.clearInterval(pendingSelectionTimer);
|
|
||||||
pendingSelectionTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
that._update();
|
that._update();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1563,7 +1511,7 @@ SelectionDisplay = (function () {
|
||||||
var wantDebug = false;
|
var wantDebug = false;
|
||||||
|
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var properties = SelectionManager.savedProperties[SelectionManager.selections[i].id];
|
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
|
||||||
var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z });
|
var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z });
|
||||||
Entities.editEntity(SelectionManager.selections[i], {
|
Entities.editEntity(SelectionManager.selections[i], {
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
|
@ -1641,7 +1589,7 @@ SelectionDisplay = (function () {
|
||||||
}
|
}
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var id = SelectionManager.selections[i];
|
var id = SelectionManager.selections[i];
|
||||||
var properties = selectionManager.savedProperties[id.id];
|
var properties = selectionManager.savedProperties[id];
|
||||||
|
|
||||||
var original = properties.position;
|
var original = properties.position;
|
||||||
var newPosition = Vec3.sum(properties.position, vector);
|
var newPosition = Vec3.sum(properties.position, vector);
|
||||||
|
@ -1900,7 +1848,7 @@ SelectionDisplay = (function () {
|
||||||
vector = change;
|
vector = change;
|
||||||
Vec3.print("Radius stretch: ", vector);
|
Vec3.print("Radius stretch: ", vector);
|
||||||
var length = vector.x + vector.y + vector.z;
|
var length = vector.x + vector.y + vector.z;
|
||||||
var props = selectionManager.savedProperties[selectionManager.selections[0].id];
|
var props = selectionManager.savedProperties[selectionManager.selections[0]];
|
||||||
|
|
||||||
var radius = props.dimensions.z / 2;
|
var radius = props.dimensions.z / 2;
|
||||||
var originalCutoff = props.cutoff;
|
var originalCutoff = props.cutoff;
|
||||||
|
@ -1917,7 +1865,7 @@ SelectionDisplay = (function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function radiusStretchFunc(vector, change) {
|
function radiusStretchFunc(vector, change) {
|
||||||
var props = selectionManager.savedProperties[selectionManager.selections[0].id];
|
var props = selectionManager.savedProperties[selectionManager.selections[0]];
|
||||||
|
|
||||||
// Find the axis being adjusted
|
// Find the axis being adjusted
|
||||||
var size;
|
var size;
|
||||||
|
@ -2084,7 +2032,7 @@ SelectionDisplay = (function () {
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var entityID = SelectionManager.selections[i];
|
var entityID = SelectionManager.selections[i];
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||||
|
|
||||||
var newProperties = {
|
var newProperties = {
|
||||||
rotation: Quat.multiply(yawChange, initialProperties.rotation),
|
rotation: Quat.multiply(yawChange, initialProperties.rotation),
|
||||||
|
@ -2211,7 +2159,7 @@ SelectionDisplay = (function () {
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var entityID = SelectionManager.selections[i];
|
var entityID = SelectionManager.selections[i];
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||||
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
|
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
|
||||||
dPos = Vec3.multiplyQbyV(pitchChange, dPos);
|
dPos = Vec3.multiplyQbyV(pitchChange, dPos);
|
||||||
|
|
||||||
|
@ -2331,7 +2279,7 @@ SelectionDisplay = (function () {
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var entityID = SelectionManager.selections[i];
|
var entityID = SelectionManager.selections[i];
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
var initialProperties = SelectionManager.savedProperties[entityID.id];
|
var initialProperties = SelectionManager.savedProperties[entityID];
|
||||||
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
|
var dPos = Vec3.subtract(initialProperties.position, initialPosition);
|
||||||
dPos = Vec3.multiplyQbyV(rollChange, dPos);
|
dPos = Vec3.multiplyQbyV(rollChange, dPos);
|
||||||
|
|
||||||
|
|
|
@ -12,17 +12,17 @@ LightOverlayManager = function() {
|
||||||
// List of overlays not currently being used
|
// List of overlays not currently being used
|
||||||
var unusedOverlays = [];
|
var unusedOverlays = [];
|
||||||
|
|
||||||
// Map from EntityItemID.id to overlay id
|
// Map from EntityItemID to overlay id
|
||||||
var entityOverlays = {};
|
var entityOverlays = {};
|
||||||
|
|
||||||
// Map from EntityItemID.id to EntityItemID object
|
// Map from EntityItemID to EntityItemID object
|
||||||
var entityIDs = {};
|
var entityIDs = {};
|
||||||
|
|
||||||
this.updatePositions = function(ids) {
|
this.updatePositions = function(ids) {
|
||||||
for (var id in entityIDs) {
|
for (var id in entityIDs) {
|
||||||
var entityID = entityIDs[id];
|
var entityID = entityIDs[id];
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
Overlays.editOverlay(entityOverlays[entityID.id], {
|
Overlays.editOverlay(entityOverlays[entityID], {
|
||||||
position: properties.position
|
position: properties.position
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -77,10 +77,10 @@ LightOverlayManager = function() {
|
||||||
|
|
||||||
function addEntity(entityID) {
|
function addEntity(entityID) {
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
var properties = Entities.getEntityProperties(entityID);
|
||||||
if (properties.type == "Light" && !(entityID.id in entityOverlays)) {
|
if (properties.type == "Light" && !(entityID in entityOverlays)) {
|
||||||
var overlay = getOverlay();
|
var overlay = getOverlay();
|
||||||
entityOverlays[entityID.id] = overlay;
|
entityOverlays[entityID] = overlay;
|
||||||
entityIDs[entityID.id] = entityID;
|
entityIDs[entityID] = entityID;
|
||||||
Overlays.editOverlay(overlay, {
|
Overlays.editOverlay(overlay, {
|
||||||
position: properties.position,
|
position: properties.position,
|
||||||
url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL,
|
url: properties.isSpotlight ? SPOT_LIGHT_URL : POINT_LIGHT_URL,
|
||||||
|
@ -94,20 +94,12 @@ LightOverlayManager = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteEntity(entityID) {
|
function deleteEntity(entityID) {
|
||||||
if (entityID.id in entityOverlays) {
|
if (entityID in entityOverlays) {
|
||||||
releaseOverlay(entityOverlays[entityID.id]);
|
releaseOverlay(entityOverlays[entityID]);
|
||||||
delete entityOverlays[entityID.id];
|
delete entityOverlays[entityID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeEntityID(oldEntityID, newEntityID) {
|
|
||||||
entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id];
|
|
||||||
entityIDs[newEntityID.id] = newEntityID;
|
|
||||||
|
|
||||||
delete entityOverlays[oldEntityID.id];
|
|
||||||
delete entityIDs[oldEntityID.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearEntities() {
|
function clearEntities() {
|
||||||
for (var id in entityOverlays) {
|
for (var id in entityOverlays) {
|
||||||
releaseOverlay(entityOverlays[id]);
|
releaseOverlay(entityOverlays[id]);
|
||||||
|
@ -117,7 +109,6 @@ LightOverlayManager = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.addingEntity.connect(addEntity);
|
Entities.addingEntity.connect(addEntity);
|
||||||
Entities.changingEntityID.connect(changeEntityID);
|
|
||||||
Entities.deletingEntity.connect(deleteEntity);
|
Entities.deletingEntity.connect(deleteEntity);
|
||||||
Entities.clearingEntities.connect(clearEntities);
|
Entities.clearingEntities.connect(clearEntities);
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,7 @@ function addIndicators(modelID) {
|
||||||
modelID.properties.sittingPoints[i].indicator = new SeatIndicator(modelID.properties, i);
|
modelID.properties.sittingPoints[i].indicator = new SeatIndicator(modelID.properties, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
models[modelID.id] = modelID;
|
models[modelID] = modelID;
|
||||||
} else {
|
} else {
|
||||||
Entities.editEntity(modelID, { glowLevel: 0.0 });
|
Entities.editEntity(modelID, { glowLevel: 0.0 });
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,7 @@ function removeIndicators(modelID) {
|
||||||
for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) {
|
for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) {
|
||||||
modelID.properties.sittingPoints[i].indicator.cleanup();
|
modelID.properties.sittingPoints[i].indicator.cleanup();
|
||||||
}
|
}
|
||||||
delete models[modelID.id];
|
delete models[modelID];
|
||||||
}
|
}
|
||||||
|
|
||||||
function showIndicators(doShow) {
|
function showIndicators(doShow) {
|
||||||
|
|
|
@ -82,11 +82,6 @@ void DatagramProcessor::processDatagrams() {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketTypeEntityAddResponse:
|
|
||||||
// this will keep creatorTokenIDs to IDs mapped correctly
|
|
||||||
EntityItemID::handleAddEntityResponse(incomingPacket);
|
|
||||||
application->getEntities()->getTree()->handleAddEntityResponse(incomingPacket);
|
|
||||||
break;
|
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
case PacketTypeOctreeStats:
|
case PacketTypeOctreeStats:
|
||||||
|
|
|
@ -68,8 +68,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory)
|
||||||
|
|
||||||
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
|
||||||
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityTreeRenderer::~EntityTreeRenderer() {
|
EntityTreeRenderer::~EntityTreeRenderer() {
|
||||||
|
@ -963,7 +963,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi
|
||||||
}
|
}
|
||||||
|
|
||||||
// makes it the unknown ID, we just released so we can't be clicking on anything
|
// makes it the unknown ID, we just released so we can't be clicking on anything
|
||||||
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID();
|
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
|
||||||
_lastMouseEvent = MouseEvent(*event, deviceID);
|
_lastMouseEvent = MouseEvent(*event, deviceID);
|
||||||
_lastMouseEventValid = true;
|
_lastMouseEventValid = true;
|
||||||
}
|
}
|
||||||
|
@ -1043,7 +1043,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
||||||
currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs);
|
currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersection.entityID.id == getID()) {
|
if (intersection.entityID == getID()) {
|
||||||
if (event->button() == Qt::MouseButton::RightButton) {
|
if (event->button() == Qt::MouseButton::RightButton) {
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
|
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type,
|
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type,
|
||||||
unsigned char* editBuffer, size_t length, int clockSkew) {
|
unsigned char* editBuffer, size_t length, int clockSkew) {
|
||||||
|
|
||||||
if (type == PacketTypeEntityAddOrEdit) {
|
if (type == PacketTypeEntityAdd || type == PacketTypeEntityEdit) {
|
||||||
EntityItem::adjustEditPacketForClockSkew(editBuffer, length, clockSkew);
|
EntityItem::adjustEditPacketForClockSkew(editBuffer, length, clockSkew);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,7 @@ bool EntityItem::_sendPhysicsUpdates = true;
|
||||||
|
|
||||||
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||||
_type(EntityTypes::Unknown),
|
_type(EntityTypes::Unknown),
|
||||||
_id(entityItemID.id),
|
_id(entityItemID),
|
||||||
_creatorTokenID(entityItemID.creatorTokenID),
|
|
||||||
_newlyCreated(false),
|
|
||||||
_lastSimulated(0),
|
_lastSimulated(0),
|
||||||
_lastUpdated(0),
|
_lastUpdated(0),
|
||||||
_lastEdited(0),
|
_lastEdited(0),
|
||||||
|
@ -351,8 +349,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
// id
|
// id
|
||||||
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
|
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
|
||||||
_id = QUuid::fromRfc4122(encodedID);
|
_id = QUuid::fromRfc4122(encodedID);
|
||||||
_creatorTokenID = UNKNOWN_ENTITY_TOKEN; // if we know the id, then we don't care about the creator token
|
|
||||||
_newlyCreated = false;
|
|
||||||
dataAt += encodedID.size();
|
dataAt += encodedID.size();
|
||||||
bytesRead += encodedID.size();
|
bytesRead += encodedID.size();
|
||||||
|
|
||||||
|
|
|
@ -96,11 +96,7 @@ public:
|
||||||
// ID and EntityItemID related methods
|
// ID and EntityItemID related methods
|
||||||
const QUuid& getID() const { return _id; }
|
const QUuid& getID() const { return _id; }
|
||||||
void setID(const QUuid& id) { _id = id; }
|
void setID(const QUuid& id) { _id = id; }
|
||||||
uint32_t getCreatorTokenID() const { return _creatorTokenID; }
|
EntityItemID getEntityItemID() const { return EntityItemID(_id); }
|
||||||
void setCreatorTokenID(uint32_t creatorTokenID) { _creatorTokenID = creatorTokenID; }
|
|
||||||
bool isNewlyCreated() const { return _newlyCreated; }
|
|
||||||
bool isKnownID() const { return getID() != UNKNOWN_ENTITY_ID; }
|
|
||||||
EntityItemID getEntityItemID() const { return EntityItemID(getID(), getCreatorTokenID(), getID() != UNKNOWN_ENTITY_ID); }
|
|
||||||
|
|
||||||
// methods for getting/setting all properties of an entity
|
// methods for getting/setting all properties of an entity
|
||||||
virtual EntityItemProperties getProperties() const;
|
virtual EntityItemProperties getProperties() const;
|
||||||
|
@ -356,8 +352,6 @@ protected:
|
||||||
static bool _sendPhysicsUpdates;
|
static bool _sendPhysicsUpdates;
|
||||||
EntityTypes::EntityType _type;
|
EntityTypes::EntityType _type;
|
||||||
QUuid _id;
|
QUuid _id;
|
||||||
uint32_t _creatorTokenID;
|
|
||||||
bool _newlyCreated;
|
|
||||||
quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes
|
quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes
|
||||||
quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes
|
quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes
|
||||||
quint64 _lastEdited; // last official local or remote edit time
|
quint64 _lastEdited; // last official local or remote edit time
|
||||||
|
|
|
@ -14,130 +14,42 @@
|
||||||
|
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
|
||||||
|
#include "RegisteredMetaTypes.h"
|
||||||
#include "EntityItemID.h"
|
#include "EntityItemID.h"
|
||||||
|
|
||||||
// for locally created models
|
|
||||||
QHash<uint32_t, QUuid> EntityItemID::_tokenIDsToIDs;
|
|
||||||
uint32_t EntityItemID::_nextCreatorTokenID = 0;
|
|
||||||
|
|
||||||
EntityItemID::EntityItemID() :
|
EntityItemID::EntityItemID() : QUuid()
|
||||||
id(NEW_ENTITY),
|
|
||||||
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
|
|
||||||
isKnownID(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemID::EntityItemID(const EntityItemID& other) :
|
|
||||||
id(other.id),
|
|
||||||
creatorTokenID(other.creatorTokenID),
|
|
||||||
isKnownID(other.isKnownID)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EntityItemID::EntityItemID(const QUuid& id, uint32_t creatorTokenID, bool isKnownID) :
|
EntityItemID::EntityItemID(const QUuid& id) : QUuid(id)
|
||||||
id(id),
|
{
|
||||||
creatorTokenID(creatorTokenID),
|
|
||||||
isKnownID(isKnownID)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityItemID::EntityItemID(const QUuid& id) :
|
|
||||||
id(id),
|
|
||||||
creatorTokenID(UNKNOWN_ENTITY_TOKEN),
|
|
||||||
isKnownID(true)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityItemID EntityItemID::getIDfromCreatorTokenID(uint32_t creatorTokenID) {
|
|
||||||
if (_tokenIDsToIDs.find(creatorTokenID) != _tokenIDsToIDs.end()) {
|
|
||||||
return EntityItemID(_tokenIDsToIDs[creatorTokenID], creatorTokenID, true);
|
|
||||||
}
|
|
||||||
return EntityItemID(UNKNOWN_ENTITY_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EntityItemID::getNextCreatorTokenID() {
|
// EntityItemID::EntityItemID(const EntityItemID& other) : QUuid(other)
|
||||||
uint32_t creatorTokenID = _nextCreatorTokenID;
|
// {
|
||||||
_nextCreatorTokenID++;
|
// }
|
||||||
return creatorTokenID;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemID EntityItemID::assignActualIDForToken() const {
|
|
||||||
EntityItemID newlyAssignedEntityID;
|
|
||||||
|
|
||||||
newlyAssignedEntityID.creatorTokenID = creatorTokenID;
|
|
||||||
newlyAssignedEntityID.isKnownID = true;
|
|
||||||
newlyAssignedEntityID.id = QUuid::createUuid();
|
|
||||||
|
|
||||||
return newlyAssignedEntityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemID EntityItemID::convertToKnownIDVersion() const {
|
|
||||||
EntityItemID knownIDVersionEntityID;
|
|
||||||
|
|
||||||
knownIDVersionEntityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
|
|
||||||
knownIDVersionEntityID.isKnownID = true;
|
|
||||||
knownIDVersionEntityID.id = id;
|
|
||||||
|
|
||||||
return knownIDVersionEntityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemID EntityItemID::convertToCreatorTokenVersion() const {
|
|
||||||
EntityItemID knownIDVersionEntityID;
|
|
||||||
|
|
||||||
knownIDVersionEntityID.creatorTokenID = creatorTokenID;
|
|
||||||
knownIDVersionEntityID.isKnownID = false;
|
|
||||||
knownIDVersionEntityID.id = UNKNOWN_ENTITY_ID;
|
|
||||||
|
|
||||||
return knownIDVersionEntityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemID EntityItemID::readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead) {
|
EntityItemID EntityItemID::readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead) {
|
||||||
EntityItemID result;
|
EntityItemID result;
|
||||||
|
|
||||||
if (bytesLeftToRead >= NUM_BYTES_RFC4122_UUID) {
|
if (bytesLeftToRead >= NUM_BYTES_RFC4122_UUID) {
|
||||||
// id
|
// id
|
||||||
QByteArray encodedID((const char*)data, NUM_BYTES_RFC4122_UUID);
|
QByteArray encodedID((const char*)data, NUM_BYTES_RFC4122_UUID);
|
||||||
result.id = QUuid::fromRfc4122(encodedID);
|
result = QUuid::fromRfc4122(encodedID);
|
||||||
result.isKnownID = true;
|
|
||||||
result.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityItemID::handleAddEntityResponse(const QByteArray& packet) {
|
|
||||||
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data());
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
|
||||||
int bytesRead = numBytesPacketHeader;
|
|
||||||
dataAt += numBytesPacketHeader;
|
|
||||||
|
|
||||||
uint32_t creatorTokenID;
|
|
||||||
memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
|
|
||||||
dataAt += sizeof(creatorTokenID);
|
|
||||||
bytesRead += sizeof(creatorTokenID);
|
|
||||||
|
|
||||||
QUuid entityID = QUuid::fromRfc4122(packet.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
|
|
||||||
dataAt += NUM_BYTES_RFC4122_UUID;
|
|
||||||
|
|
||||||
// add our token to id mapping
|
|
||||||
_tokenIDsToIDs[creatorTokenID] = entityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue EntityItemID::toScriptValue(QScriptEngine* engine) const {
|
QScriptValue EntityItemID::toScriptValue(QScriptEngine* engine) const {
|
||||||
return EntityItemIDtoScriptValue(engine, *this);
|
return EntityItemIDtoScriptValue(engine, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& id) {
|
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& id) {
|
||||||
QScriptValue obj = engine->newObject();
|
return quuidToScriptValue(engine, id);
|
||||||
obj.setProperty("id", id.id.toString());
|
|
||||||
obj.setProperty("creatorTokenID", id.creatorTokenID);
|
|
||||||
obj.setProperty("isKnownID", id.isKnownID);
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
|
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
|
||||||
id.id = QUuid(object.property("id").toVariant().toString());
|
quuidFromScriptValue(object, id);
|
||||||
id.creatorTokenID = object.property("creatorTokenID").toVariant().toUInt();
|
|
||||||
id.isKnownID = object.property("isKnownID").toVariant().toBool();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,87 +20,40 @@
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
const uint32_t UNKNOWN_ENTITY_TOKEN = 0xFFFFFFFF;
|
const QUuid UNKNOWN_ENTITY_ID; // null uuid
|
||||||
|
|
||||||
//const uint32_t NEW_ENTITY = 0xFFFFFFFF;
|
/// Abstract ID for editing model items. Used in EntityItem JS API.
|
||||||
//const uint32_t UNKNOWN_ENTITY_ID = 0xFFFFFFFF;
|
class EntityItemID : public QUuid {
|
||||||
|
|
||||||
const QUuid NEW_ENTITY;
|
|
||||||
const QUuid UNKNOWN_ENTITY_ID;
|
|
||||||
|
|
||||||
|
|
||||||
/// Abstract ID for editing model items. Used in EntityItem JS API - When models are created in the JS api, they are given a
|
|
||||||
/// local creatorTokenID, the actual id for the model is not known until the server responds to the creator with the
|
|
||||||
/// correct mapping. This class works with the scripting API an allows the developer to edit models they created.
|
|
||||||
class EntityItemID {
|
|
||||||
public:
|
public:
|
||||||
EntityItemID();
|
EntityItemID();
|
||||||
EntityItemID(const EntityItemID& other);
|
|
||||||
EntityItemID(const QUuid& id, uint32_t creatorTokenID, bool isKnownID);
|
|
||||||
EntityItemID(const QUuid& id);
|
EntityItemID(const QUuid& id);
|
||||||
|
// EntityItemID(const EntityItemID& other);
|
||||||
//uint32_t id;
|
|
||||||
QUuid id;
|
|
||||||
|
|
||||||
uint32_t creatorTokenID;
|
|
||||||
bool isKnownID;
|
|
||||||
|
|
||||||
// these methods will reduce the ID down to half the IDs data to allow for comparisons and searches of known values
|
|
||||||
EntityItemID convertToKnownIDVersion() const;
|
|
||||||
EntityItemID convertToCreatorTokenVersion() const;
|
|
||||||
|
|
||||||
bool isInvalidID() const { return id == UNKNOWN_ENTITY_ID && creatorTokenID == UNKNOWN_ENTITY_TOKEN && isKnownID == false; }
|
|
||||||
|
|
||||||
// these methods allow you to create models, and later edit them.
|
|
||||||
static EntityItemID createInvalidEntityID() { return EntityItemID(UNKNOWN_ENTITY_ID, UNKNOWN_ENTITY_TOKEN, false); }
|
|
||||||
static EntityItemID getIDfromCreatorTokenID(uint32_t creatorTokenID);
|
|
||||||
static uint32_t getNextCreatorTokenID();
|
|
||||||
static void handleAddEntityResponse(const QByteArray& packet);
|
|
||||||
static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead);
|
static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead);
|
||||||
|
|
||||||
QScriptValue toScriptValue(QScriptEngine* engine) const;
|
QScriptValue toScriptValue(QScriptEngine* engine) const;
|
||||||
|
|
||||||
private:
|
|
||||||
friend class EntityTree;
|
|
||||||
EntityItemID assignActualIDForToken() const; // only called by EntityTree
|
|
||||||
|
|
||||||
static uint32_t _nextCreatorTokenID; /// used by the static interfaces for creator token ids
|
bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; }
|
||||||
static QHash<uint32_t, QUuid> _tokenIDsToIDs;
|
|
||||||
|
// QUuid id;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
|
// inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
|
||||||
return (a.id == b.id) ? (a.creatorTokenID < b.creatorTokenID) : (a.id < b.id);
|
// return a.id < b.id;
|
||||||
}
|
// }
|
||||||
|
|
||||||
inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
|
// inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
|
||||||
if (a.isInvalidID() && b.isInvalidID()) {
|
// return a.id == b.id;
|
||||||
return true;
|
// }
|
||||||
}
|
|
||||||
if (a.isInvalidID() != b.isInvalidID()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a.id == UNKNOWN_ENTITY_ID || b.id == UNKNOWN_ENTITY_ID) {
|
|
||||||
return a.creatorTokenID == b.creatorTokenID;
|
|
||||||
}
|
|
||||||
return a.id == b.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator!=(const EntityItemID& a, const EntityItemID& b) {
|
// inline bool operator!=(const EntityItemID& a, const EntityItemID& b) {
|
||||||
return !(a == b);
|
// return !(a == b);
|
||||||
}
|
// }
|
||||||
|
|
||||||
inline uint qHash(const EntityItemID& a, uint seed) {
|
// inline uint qHash(const EntityItemID& a, uint seed) {
|
||||||
QUuid temp;
|
// return qHash(a.id, seed);
|
||||||
if (a.id == UNKNOWN_ENTITY_ID) {
|
// }
|
||||||
temp = QUuid(a.creatorTokenID,0,0,0,0,0,0,0,0,0,0);
|
|
||||||
} else {
|
|
||||||
temp = a.id;
|
|
||||||
}
|
|
||||||
return qHash(temp, seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
|
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
|
||||||
debug << "[ id:" << id.id << ", creatorTokenID:" << id.creatorTokenID << ", isKnownID:" << id.isKnownID << "]";
|
debug << "[entity-id:" << id.toString() << "]";
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -350,9 +350,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
||||||
|
|
||||||
if (_idSet) {
|
if (_idSet) {
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(isKnownID, (_id != UNKNOWN_ENTITY_ID));
|
|
||||||
} else {
|
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(isKnownID, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
|
||||||
|
@ -561,7 +558,7 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
|
||||||
// TODO: Implement support for script and visible properties.
|
// TODO: Implement support for script and visible properties.
|
||||||
//
|
//
|
||||||
bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
||||||
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
||||||
OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too.
|
OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too.
|
||||||
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
|
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
|
||||||
|
|
||||||
|
@ -586,23 +583,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
if (success) {
|
if (success) {
|
||||||
|
|
||||||
// Now add our edit content details...
|
// Now add our edit content details...
|
||||||
bool isNewEntityItem = (id.id == NEW_ENTITY);
|
|
||||||
|
|
||||||
// id
|
// id
|
||||||
// encode our ID as a byte count coded byte stream
|
// encode our ID as a byte count coded byte stream
|
||||||
QByteArray encodedID = id.id.toRfc4122(); // NUM_BYTES_RFC4122_UUID
|
QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID
|
||||||
|
|
||||||
// encode our ID as a byte count coded byte stream
|
// encode our ID as a byte count coded byte stream
|
||||||
ByteCountCoded<quint32> tokenCoder;
|
ByteCountCoded<quint32> tokenCoder;
|
||||||
QByteArray encodedToken;
|
QByteArray encodedToken;
|
||||||
|
|
||||||
// special case for handling "new" modelItems
|
|
||||||
if (isNewEntityItem) {
|
|
||||||
// encode our creator token as a byte count coded byte stream
|
|
||||||
tokenCoder = id.creatorTokenID;
|
|
||||||
encodedToken = tokenCoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode our type as a byte count coded byte stream
|
// encode our type as a byte count coded byte stream
|
||||||
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
|
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
|
||||||
QByteArray encodedType = typeCoder;
|
QByteArray encodedType = typeCoder;
|
||||||
|
@ -631,7 +620,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
bool successLastEditedFits = packetData->appendValue(lastEdited);
|
bool successLastEditedFits = packetData->appendValue(lastEdited);
|
||||||
|
|
||||||
bool successIDFits = packetData->appendValue(encodedID);
|
bool successIDFits = packetData->appendValue(encodedID);
|
||||||
if (isNewEntityItem && successIDFits) {
|
if (successIDFits) {
|
||||||
successIDFits = packetData->appendValue(encodedToken);
|
successIDFits = packetData->appendValue(encodedToken);
|
||||||
}
|
}
|
||||||
bool successTypeFits = packetData->appendValue(encodedType);
|
bool successTypeFits = packetData->appendValue(encodedType);
|
||||||
|
@ -829,7 +818,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
// TODO: Implement support for script and visible properties.
|
// TODO: Implement support for script and visible properties.
|
||||||
//
|
//
|
||||||
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||||
EntityItemID& entityID, EntityItemProperties& properties) {
|
EntityItemID& entityID, EntityItemProperties& properties) {
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
|
||||||
const unsigned char* dataAt = data;
|
const unsigned char* dataAt = data;
|
||||||
|
@ -863,36 +852,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
dataAt += encodedID.size();
|
dataAt += encodedID.size();
|
||||||
processedBytes += encodedID.size();
|
processedBytes += encodedID.size();
|
||||||
|
|
||||||
bool isNewEntityItem = (editID == NEW_ENTITY);
|
entityID = editID;
|
||||||
|
valid = true;
|
||||||
if (isNewEntityItem) {
|
|
||||||
// If this is a NEW_ENTITY, then we assume that there's an additional uint32_t creatorToken, that
|
|
||||||
// we want to send back to the creator as an map to the actual id
|
|
||||||
|
|
||||||
QByteArray encodedToken((const char*)dataAt, (bytesToRead - processedBytes));
|
|
||||||
ByteCountCoded<quint32> tokenCoder = encodedToken;
|
|
||||||
quint32 creatorTokenID = tokenCoder;
|
|
||||||
encodedToken = tokenCoder; // determine true bytesToRead
|
|
||||||
dataAt += encodedToken.size();
|
|
||||||
processedBytes += encodedToken.size();
|
|
||||||
|
|
||||||
//newEntityItem.setCreatorTokenID(creatorTokenID);
|
|
||||||
//newEntityItem._newlyCreated = true;
|
|
||||||
|
|
||||||
entityID.id = NEW_ENTITY;
|
|
||||||
entityID.creatorTokenID = creatorTokenID;
|
|
||||||
entityID.isKnownID = false;
|
|
||||||
|
|
||||||
valid = true;
|
|
||||||
|
|
||||||
// created time is lastEdited time
|
|
||||||
properties.setCreated(lastEdited);
|
|
||||||
} else {
|
|
||||||
entityID.id = editID;
|
|
||||||
entityID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
|
|
||||||
entityID.isKnownID = true;
|
|
||||||
valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entity Type...
|
// Entity Type...
|
||||||
QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
|
QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
|
||||||
|
@ -1015,7 +976,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
// header it does not include the send times and sequence number because that is handled by the
|
// header it does not include the send times and sequence number because that is handled by the
|
||||||
// edit packet sender...
|
// edit packet sender...
|
||||||
bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID,
|
bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID,
|
||||||
unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) {
|
unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) {
|
||||||
|
|
||||||
unsigned char* copyAt = outputBuffer;
|
unsigned char* copyAt = outputBuffer;
|
||||||
uint16_t numberOfIds = 1; // only one entity ID in this message
|
uint16_t numberOfIds = 1; // only one entity ID in this message
|
||||||
|
@ -1029,7 +990,7 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt
|
||||||
copyAt += sizeof(numberOfIds);
|
copyAt += sizeof(numberOfIds);
|
||||||
outputLength = sizeof(numberOfIds);
|
outputLength = sizeof(numberOfIds);
|
||||||
|
|
||||||
QUuid entityID = entityItemID.id;
|
QUuid entityID = entityItemID;
|
||||||
QByteArray encodedEntityID = entityID.toRfc4122();
|
QByteArray encodedEntityID = entityID.toRfc4122();
|
||||||
|
|
||||||
memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID);
|
memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID);
|
||||||
|
|
|
@ -71,9 +71,6 @@ public:
|
||||||
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
{ return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; }
|
||||||
EntityPropertyFlags getChangedProperties() const;
|
EntityPropertyFlags getChangedProperties() const;
|
||||||
|
|
||||||
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
|
|
||||||
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
|
|
||||||
|
|
||||||
AACube getMaximumAACube() const;
|
AACube getMaximumAACube() const;
|
||||||
AABox getAABox() const;
|
AABox getAABox() const;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
|
|
||||||
EntityScriptingInterface::EntityScriptingInterface() :
|
EntityScriptingInterface::EntityScriptingInterface() :
|
||||||
_nextCreatorTokenID(0),
|
|
||||||
_entityTree(NULL)
|
_entityTree(NULL)
|
||||||
{
|
{
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
@ -29,7 +28,7 @@ EntityScriptingInterface::EntityScriptingInterface() :
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
|
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
|
||||||
EntityItemID entityID, const EntityItemProperties& properties) {
|
EntityItemID entityID, const EntityItemProperties& properties) {
|
||||||
getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties);
|
getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +46,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
disconnect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
|
disconnect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
|
||||||
disconnect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
|
disconnect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
|
||||||
disconnect(_entityTree, &EntityTree::changingEntityID, this, &EntityScriptingInterface::changingEntityID);
|
|
||||||
disconnect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
|
disconnect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +54,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
connect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
|
connect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);
|
||||||
connect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
|
connect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);
|
||||||
connect(_entityTree, &EntityTree::changingEntityID, this, &EntityScriptingInterface::changingEntityID);
|
|
||||||
connect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
|
connect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,14 +68,11 @@ void bidForSimulationOwnership(EntityItemProperties& properties) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
|
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
|
||||||
|
|
||||||
// The application will keep track of creatorTokenID
|
|
||||||
uint32_t creatorTokenID = EntityItemID::getNextCreatorTokenID();
|
|
||||||
|
|
||||||
EntityItemProperties propertiesWithSimID = properties;
|
EntityItemProperties propertiesWithSimID = properties;
|
||||||
|
|
||||||
EntityItemID id(NEW_ENTITY, creatorTokenID, false);
|
EntityItemID id = EntityItemID(QUuid::createUuid());
|
||||||
|
|
||||||
// If we have a local entity tree set, then also update it.
|
// If we have a local entity tree set, then also update it.
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
@ -98,34 +92,17 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
|
||||||
|
|
||||||
// queue the packet
|
// queue the packet
|
||||||
if (success) {
|
if (success) {
|
||||||
queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID);
|
queueEntityMessage(PacketTypeEntityAdd, id, propertiesWithSimID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemID EntityScriptingInterface::identifyEntity(EntityItemID entityID) {
|
EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {
|
||||||
EntityItemID actualID = entityID;
|
|
||||||
|
|
||||||
if (!entityID.isKnownID) {
|
|
||||||
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
|
|
||||||
if (actualID == UNKNOWN_ENTITY_ID) {
|
|
||||||
return entityID; // bailing early
|
|
||||||
}
|
|
||||||
|
|
||||||
// found it!
|
|
||||||
entityID.id = actualID.id;
|
|
||||||
entityID.isKnownID = true;
|
|
||||||
}
|
|
||||||
return entityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID entityID) {
|
|
||||||
EntityItemProperties results;
|
EntityItemProperties results;
|
||||||
EntityItemID identity = identifyEntity(entityID);
|
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForRead();
|
_entityTree->lockForRead();
|
||||||
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(identity));
|
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(EntityItemID(identity)));
|
||||||
|
|
||||||
if (entity) {
|
if (entity) {
|
||||||
results = entity->getProperties();
|
results = entity->getProperties();
|
||||||
|
@ -142,8 +119,6 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
results.setIsUnknownID();
|
|
||||||
}
|
}
|
||||||
_entityTree->unlock();
|
_entityTree->unlock();
|
||||||
}
|
}
|
||||||
|
@ -151,67 +126,42 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const EntityItemProperties& properties) {
|
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties) {
|
||||||
EntityItemID actualID = entityID;
|
EntityItemID entityID(id);
|
||||||
// if the entity is unknown, attempt to look it up
|
// If we have a local entity tree set, then also update it.
|
||||||
if (!entityID.isKnownID) {
|
|
||||||
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
|
|
||||||
if (actualID.id != UNKNOWN_ENTITY_ID) {
|
|
||||||
entityID.id = actualID.id;
|
|
||||||
entityID.isKnownID = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a local entity tree set, then also update it. We can do this even if we don't know
|
|
||||||
// the actual id, because we can edit out local entities just with creatorTokenID
|
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForWrite();
|
_entityTree->lockForWrite();
|
||||||
_entityTree->updateEntity(entityID, properties);
|
_entityTree->updateEntity(entityID, properties);
|
||||||
_entityTree->unlock();
|
_entityTree->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if at this point, we know the id, send the update to the entity server
|
// make sure the properties has a type, so that the encode can know which properties to include
|
||||||
if (entityID.isKnownID) {
|
if (properties.getType() == EntityTypes::Unknown) {
|
||||||
// make sure the properties has a type, so that the encode can know which properties to include
|
EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||||
if (properties.getType() == EntityTypes::Unknown) {
|
if (entity) {
|
||||||
EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID);
|
// we need to change the outgoing properties, so we make a copy, modify, and send.
|
||||||
if (entity) {
|
EntityItemProperties modifiedProperties = properties;
|
||||||
// we need to change the outgoing properties, so we make a copy, modify, and send.
|
entity->setLastBroadcast(usecTimestampNow());
|
||||||
EntityItemProperties modifiedProperties = properties;
|
modifiedProperties.setType(entity->getType());
|
||||||
entity->setLastBroadcast(usecTimestampNow());
|
bidForSimulationOwnership(modifiedProperties);
|
||||||
modifiedProperties.setType(entity->getType());
|
queueEntityMessage(PacketTypeEntityEdit, entityID, modifiedProperties);
|
||||||
bidForSimulationOwnership(modifiedProperties);
|
return id;
|
||||||
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, modifiedProperties);
|
|
||||||
return entityID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return entityID;
|
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
|
void EntityScriptingInterface::deleteEntity(QUuid id) {
|
||||||
|
EntityItemID entityID(id);
|
||||||
EntityItemID actualID = entityID;
|
|
||||||
|
|
||||||
// if the entity is unknown, attempt to look it up
|
|
||||||
if (!entityID.isKnownID) {
|
|
||||||
actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID);
|
|
||||||
if (actualID.id != UNKNOWN_ENTITY_ID) {
|
|
||||||
entityID.id = actualID.id;
|
|
||||||
entityID.isKnownID = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shouldDelete = true;
|
bool shouldDelete = true;
|
||||||
|
|
||||||
// If we have a local entity tree set, then also update it.
|
// If we have a local entity tree set, then also update it.
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForWrite();
|
_entityTree->lockForWrite();
|
||||||
|
|
||||||
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(actualID));
|
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(entityID));
|
||||||
if (entity) {
|
if (entity) {
|
||||||
if (entity->getLocked()) {
|
if (entity->getLocked()) {
|
||||||
shouldDelete = false;
|
shouldDelete = false;
|
||||||
|
@ -224,13 +174,13 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if at this point, we know the id, and we should still delete the entity, send the update to the entity server
|
// if at this point, we know the id, and we should still delete the entity, send the update to the entity server
|
||||||
if (shouldDelete && entityID.isKnownID) {
|
if (shouldDelete) {
|
||||||
getEntityPacketSender()->queueEraseEntityMessage(entityID);
|
getEntityPacketSender()->queueEraseEntityMessage(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemID EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
|
QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const {
|
||||||
EntityItemID result(UNKNOWN_ENTITY_ID, UNKNOWN_ENTITY_TOKEN, false);
|
EntityItemID result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForRead();
|
_entityTree->lockForRead();
|
||||||
const EntityItem* closestEntity = _entityTree->findClosestEntity(center, radius);
|
const EntityItem* closestEntity = _entityTree->findClosestEntity(center, radius);
|
||||||
|
@ -251,8 +201,8 @@ void EntityScriptingInterface::dumpTree() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<EntityItemID> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
|
QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
|
||||||
QVector<EntityItemID> result;
|
QVector<QUuid> result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForRead();
|
_entityTree->lockForRead();
|
||||||
QVector<const EntityItem*> entities;
|
QVector<const EntityItem*> entities;
|
||||||
|
@ -266,8 +216,8 @@ QVector<EntityItemID> EntityScriptingInterface::findEntities(const glm::vec3& ce
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<EntityItemID> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const {
|
QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const {
|
||||||
QVector<EntityItemID> result;
|
QVector<QUuid> result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForRead();
|
_entityTree->lockForRead();
|
||||||
AABox box(corner, dimensions);
|
AABox box(corner, dimensions);
|
||||||
|
@ -403,9 +353,8 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
|
||||||
value.intersects = object.property("intersects").toVariant().toBool();
|
value.intersects = object.property("intersects").toVariant().toBool();
|
||||||
value.accurate = object.property("accurate").toVariant().toBool();
|
value.accurate = object.property("accurate").toVariant().toBool();
|
||||||
QScriptValue entityIDValue = object.property("entityID");
|
QScriptValue entityIDValue = object.property("entityID");
|
||||||
if (entityIDValue.isValid()) {
|
// EntityItemIDfromScriptValue(entityIDValue, value.entityID);
|
||||||
EntityItemIDfromScriptValue(entityIDValue, value.entityID);
|
quuidFromScriptValue(entityIDValue, value.entityID);
|
||||||
}
|
|
||||||
QScriptValue entityPropertiesValue = object.property("properties");
|
QScriptValue entityPropertiesValue = object.property("properties");
|
||||||
if (entityPropertiesValue.isValid()) {
|
if (entityPropertiesValue.isValid()) {
|
||||||
EntityItemPropertiesFromScriptValue(entityPropertiesValue, value.properties);
|
EntityItemPropertiesFromScriptValue(entityPropertiesValue, value.properties);
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
RayToEntityIntersectionResult();
|
RayToEntityIntersectionResult();
|
||||||
bool intersects;
|
bool intersects;
|
||||||
bool accurate;
|
bool accurate;
|
||||||
EntityItemID entityID;
|
QUuid entityID;
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
float distance;
|
float distance;
|
||||||
BoxFace face;
|
BoxFace face;
|
||||||
|
@ -70,34 +70,31 @@ public slots:
|
||||||
Q_INVOKABLE bool canRez();
|
Q_INVOKABLE bool canRez();
|
||||||
|
|
||||||
/// adds a model with the specific properties
|
/// adds a model with the specific properties
|
||||||
Q_INVOKABLE EntityItemID addEntity(const EntityItemProperties& properties);
|
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties);
|
||||||
|
|
||||||
/// identify a recently created model to determine its true ID
|
|
||||||
Q_INVOKABLE EntityItemID identifyEntity(EntityItemID entityID);
|
|
||||||
|
|
||||||
/// gets the current model properties for a specific model
|
/// gets the current model properties for a specific model
|
||||||
/// this function will not find return results in script engine contexts which don't have access to models
|
/// this function will not find return results in script engine contexts which don't have access to models
|
||||||
Q_INVOKABLE EntityItemProperties getEntityProperties(EntityItemID entityID);
|
Q_INVOKABLE EntityItemProperties getEntityProperties(QUuid entityID);
|
||||||
|
|
||||||
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
|
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
|
||||||
/// successful edit, if the input entityID is for an unknown model this function will have no effect
|
/// successful edit, if the input entityID is for an unknown model this function will have no effect
|
||||||
Q_INVOKABLE EntityItemID editEntity(EntityItemID entityID, const EntityItemProperties& properties);
|
Q_INVOKABLE QUuid editEntity(QUuid entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
/// deletes a model
|
/// deletes a model
|
||||||
Q_INVOKABLE void deleteEntity(EntityItemID entityID);
|
Q_INVOKABLE void deleteEntity(QUuid entityID);
|
||||||
|
|
||||||
/// finds the closest model to the center point, within the radius
|
/// finds the closest model to the center point, within the radius
|
||||||
/// will return a EntityItemID.isKnownID = false if no models are in the radius
|
/// will return a EntityItemID.isKnownID = false if no models are in the radius
|
||||||
/// this function will not find any models in script engine contexts which don't have access to models
|
/// this function will not find any models in script engine contexts which don't have access to models
|
||||||
Q_INVOKABLE EntityItemID findClosestEntity(const glm::vec3& center, float radius) const;
|
Q_INVOKABLE QUuid findClosestEntity(const glm::vec3& center, float radius) const;
|
||||||
|
|
||||||
/// finds models within the search sphere specified by the center point and radius
|
/// finds models within the search sphere specified by the center point and radius
|
||||||
/// this function will not find any models in script engine contexts which don't have access to models
|
/// this function will not find any models in script engine contexts which don't have access to models
|
||||||
Q_INVOKABLE QVector<EntityItemID> findEntities(const glm::vec3& center, float radius) const;
|
Q_INVOKABLE QVector<QUuid> findEntities(const glm::vec3& center, float radius) const;
|
||||||
|
|
||||||
/// finds models within the search sphere specified by the center point and radius
|
/// finds models within the search sphere specified by the center point and radius
|
||||||
/// this function will not find any models in script engine contexts which don't have access to models
|
/// this function will not find any models in script engine contexts which don't have access to models
|
||||||
Q_INVOKABLE QVector<EntityItemID> findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
|
Q_INVOKABLE QVector<QUuid> findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
|
||||||
|
|
||||||
/// If the scripting context has visible entities, this will determine a ray intersection, the results
|
/// If the scripting context has visible entities, this will determine a ray intersection, the results
|
||||||
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
|
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
|
||||||
|
@ -145,7 +142,6 @@ signals:
|
||||||
|
|
||||||
void deletingEntity(const EntityItemID& entityID);
|
void deletingEntity(const EntityItemID& entityID);
|
||||||
void addingEntity(const EntityItemID& entityID);
|
void addingEntity(const EntityItemID& entityID);
|
||||||
void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID);
|
|
||||||
void clearingEntities();
|
void clearingEntities();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -155,7 +151,6 @@ private:
|
||||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||||
bool precisionPicking);
|
bool precisionPicking);
|
||||||
|
|
||||||
uint32_t _nextCreatorTokenID;
|
|
||||||
EntityTree* _entityTree;
|
EntityTree* _entityTree;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,8 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
||||||
bool EntityTree::handlesEditPacketType(PacketType packetType) const {
|
bool EntityTree::handlesEditPacketType(PacketType packetType) const {
|
||||||
// we handle these types of "edit" packets
|
// we handle these types of "edit" packets
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case PacketTypeEntityAddOrEdit:
|
case PacketTypeEntityAdd:
|
||||||
|
case PacketTypeEntityEdit:
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -230,19 +231,11 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems
|
|
||||||
// that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs.
|
|
||||||
bool recordCreationTime = false;
|
bool recordCreationTime = false;
|
||||||
if (!entityID.isKnownID) {
|
if (properties.getCreated() == UNKNOWN_CREATED_TIME) {
|
||||||
if (getIsServer()) {
|
// the entity's creation time was not specified in properties, which means this is a NEW entity
|
||||||
qCDebug(entities) << "UNEXPECTED!!! ----- EntityTree::addEntity()... (getIsSever() && !entityID.isKnownID)";
|
// and we must record its creation time
|
||||||
return result;
|
recordCreationTime = true;
|
||||||
}
|
|
||||||
if (properties.getCreated() == UNKNOWN_CREATED_TIME) {
|
|
||||||
// the entity's creation time was not specified in properties, which means this is a NEW entity
|
|
||||||
// and we must record its creation time
|
|
||||||
recordCreationTime = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
||||||
|
@ -375,7 +368,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
|
||||||
// set up the deleted entities ID
|
// set up the deleted entities ID
|
||||||
quint64 deletedAt = usecTimestampNow();
|
quint64 deletedAt = usecTimestampNow();
|
||||||
_recentlyDeletedEntitiesLock.lockForWrite();
|
_recentlyDeletedEntitiesLock.lockForWrite();
|
||||||
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID().id);
|
_recentlyDeletedEntityItemIDs.insert(deletedAt, theEntity->getEntityItemID());
|
||||||
_recentlyDeletedEntitiesLock.unlock();
|
_recentlyDeletedEntitiesLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,95 +382,6 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is used to find and fix entity IDs that are shifting from creator token based to known ID based entity IDs.
|
|
||||||
/// This should only be used on a client side (viewing) tree. The typical usage is that a local editor has been creating
|
|
||||||
/// entities in the local tree, those entities have creatorToken based entity IDs. But those entity edits are also sent up to
|
|
||||||
/// the server, and the server eventually sends back to the client two messages that can come in varying order. The first
|
|
||||||
/// message would be a typical query/viewing data message conversation in which the viewer "sees" the newly created entity.
|
|
||||||
/// Those entities that have been seen, will have the authoritative "known ID". Therefore there is a potential that there can
|
|
||||||
/// be two copies of the same entity in the tree: the "local only" "creator token" version of the entity and the "seen"
|
|
||||||
/// "knownID" version of the entity. The server also sends an "entityAdded" message to the client which contains the mapping
|
|
||||||
/// of the creator token to the known ID. These messages can come in any order, so we need to handle the follow cases:
|
|
||||||
///
|
|
||||||
/// Case A: The local edit occurs, the addEntity message arrives, the "viewed data" has not yet arrived.
|
|
||||||
/// In this case, we can expect that our local tree has only one copy of the entity (the creator token),
|
|
||||||
/// and we only really need to fix up that entity with a new version of the ID that includes the knownID
|
|
||||||
///
|
|
||||||
/// Case B: The local edit occurs, the "viewed data" for the new entity arrives, then the addEntity message arrives.
|
|
||||||
/// In this case, we can expect that our local tree has two copies of the entity (the creator token, and the
|
|
||||||
/// known ID version). We end up with two version of the entity because the server sends viewers only the
|
|
||||||
/// known ID version without a creator token. And we don't yet know the mapping until we get the mapping message.
|
|
||||||
/// In this case we need to fix up that entity with a new version of the ID that includes the knownID and
|
|
||||||
/// we need to delete the extra copy of the entity.
|
|
||||||
///
|
|
||||||
/// This method handles both of these cases.
|
|
||||||
///
|
|
||||||
/// NOTE: unlike some operations on the tree, this process does not mark the tree as being changed. This is because
|
|
||||||
/// we're not changing the content of the tree, we're only changing the internal IDs that map entities from creator
|
|
||||||
/// based to known IDs. This means we don't have to recurse the tree to mark the changed path as dirty.
|
|
||||||
void EntityTree::handleAddEntityResponse(const QByteArray& packet) {
|
|
||||||
|
|
||||||
if (!getIsClient()) {
|
|
||||||
qCDebug(entities) << "UNEXPECTED!!! EntityTree::handleAddEntityResponse() with !getIsClient() ***";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data());
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
|
||||||
int bytesRead = numBytesPacketHeader;
|
|
||||||
dataAt += numBytesPacketHeader;
|
|
||||||
|
|
||||||
uint32_t creatorTokenID;
|
|
||||||
memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID));
|
|
||||||
dataAt += sizeof(creatorTokenID);
|
|
||||||
bytesRead += sizeof(creatorTokenID);
|
|
||||||
|
|
||||||
QUuid entityID = QUuid::fromRfc4122(packet.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
|
|
||||||
dataAt += NUM_BYTES_RFC4122_UUID;
|
|
||||||
|
|
||||||
// First, look for the existing entity in the tree..
|
|
||||||
EntityItemID searchEntityID;
|
|
||||||
searchEntityID.id = entityID;
|
|
||||||
searchEntityID.creatorTokenID = creatorTokenID;
|
|
||||||
|
|
||||||
lockForWrite();
|
|
||||||
|
|
||||||
// find the creator token version, it's containing element, and the entity itself
|
|
||||||
EntityItem* foundEntity = NULL;
|
|
||||||
EntityItemID creatorTokenVersion = searchEntityID.convertToCreatorTokenVersion();
|
|
||||||
EntityItemID knownIDVersion = searchEntityID.convertToKnownIDVersion();
|
|
||||||
|
|
||||||
_changedEntityIDs[creatorTokenVersion] = knownIDVersion;
|
|
||||||
|
|
||||||
// First look for and find the "viewed version" of this entity... it's possible we got
|
|
||||||
// the known ID version sent to us between us creating our local version, and getting this
|
|
||||||
// remapping message. If this happened, we actually want to find and delete that version of
|
|
||||||
// the entity.
|
|
||||||
EntityTreeElement* knownIDVersionContainingElement = getContainingElement(knownIDVersion);
|
|
||||||
if (knownIDVersionContainingElement) {
|
|
||||||
foundEntity = knownIDVersionContainingElement->getEntityWithEntityItemID(knownIDVersion);
|
|
||||||
if (foundEntity) {
|
|
||||||
knownIDVersionContainingElement->removeEntityWithEntityItemID(knownIDVersion);
|
|
||||||
setContainingElement(knownIDVersion, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityTreeElement* creatorTokenContainingElement = getContainingElement(creatorTokenVersion);
|
|
||||||
if (creatorTokenContainingElement) {
|
|
||||||
foundEntity = creatorTokenContainingElement->getEntityWithEntityItemID(creatorTokenVersion);
|
|
||||||
if (foundEntity) {
|
|
||||||
creatorTokenContainingElement->updateEntityItemID(creatorTokenVersion, knownIDVersion);
|
|
||||||
setContainingElement(creatorTokenVersion, NULL);
|
|
||||||
setContainingElement(knownIDVersion, creatorTokenContainingElement);
|
|
||||||
|
|
||||||
// because the ID of the entity is switching, we need to emit these signals for any
|
|
||||||
// listeners who care about the changing of IDs
|
|
||||||
emit changingEntityID(creatorTokenVersion, knownIDVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FindNearPointArgs {
|
class FindNearPointArgs {
|
||||||
public:
|
public:
|
||||||
|
@ -635,30 +539,12 @@ EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /
|
||||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||||
if (containingElement) {
|
if (containingElement) {
|
||||||
foundEntity = containingElement->getEntityWithEntityItemID(entityID);
|
foundEntity = containingElement->getEntityWithEntityItemID(entityID);
|
||||||
if (!foundEntity && _changedEntityIDs.contains(entityID)) {
|
|
||||||
foundEntity = containingElement->getEntityWithEntityItemID(_changedEntityIDs[entityID]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return foundEntity;
|
return foundEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemID EntityTree::assignEntityID(const EntityItemID& entityItemID) {
|
|
||||||
if (!getIsServer()) {
|
|
||||||
qCDebug(entities) << "UNEXPECTED!!! assignEntityID should only be called on a server tree. entityItemID:" << entityItemID;
|
|
||||||
return entityItemID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getContainingElement(entityItemID)) {
|
|
||||||
qCDebug(entities) << "UNEXPECTED!!! don't call assignEntityID() for existing entityIDs. entityItemID:" << entityItemID;
|
|
||||||
return entityItemID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The EntityItemID is responsible for assigning actual IDs and keeping track of them.
|
|
||||||
return entityItemID.assignActualIDForToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
int EntityTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
int EntityTree::processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
|
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
|
||||||
|
|
||||||
if (!getIsServer()) {
|
if (!getIsServer()) {
|
||||||
qCDebug(entities) << "UNEXPECTED!!! processEditPacketData() should only be called on a server tree.";
|
qCDebug(entities) << "UNEXPECTED!!! processEditPacketData() should only be called on a server tree.";
|
||||||
|
@ -674,40 +560,34 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PacketTypeEntityAddOrEdit: {
|
case PacketTypeEntityAdd:
|
||||||
|
case PacketTypeEntityEdit: {
|
||||||
EntityItemID entityItemID;
|
EntityItemID entityItemID;
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength,
|
bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength,
|
||||||
processedBytes, entityItemID, properties);
|
processedBytes, entityItemID, properties);
|
||||||
|
|
||||||
// If we got a valid edit packet, then it could be a new entity or it could be an update to
|
// If we got a valid edit packet, then it could be a new entity or it could be an update to
|
||||||
// an existing entity... handle appropriately
|
// an existing entity... handle appropriately
|
||||||
if (validEditPacket) {
|
if (validEditPacket) {
|
||||||
|
// search for the entity by EntityItemID
|
||||||
// If this is a knownID, then it should exist in our tree
|
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
|
||||||
if (entityItemID.isKnownID) {
|
if (existingEntity && packetType == PacketTypeEntityEdit) {
|
||||||
// search for the entity by EntityItemID
|
|
||||||
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
|
|
||||||
|
|
||||||
// if the EntityItem exists, then update it
|
// if the EntityItem exists, then update it
|
||||||
if (existingEntity) {
|
if (wantEditLogging()) {
|
||||||
if (wantEditLogging()) {
|
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
|
||||||
qCDebug(entities) << "User [" << senderNode->getUUID() << "] editing entity. ID:" << entityItemID;
|
qCDebug(entities) << " properties:" << properties;
|
||||||
qCDebug(entities) << " properties:" << properties;
|
|
||||||
}
|
|
||||||
updateEntity(entityItemID, properties, senderNode);
|
|
||||||
existingEntity->markAsChangedOnServer();
|
|
||||||
} else {
|
|
||||||
qCDebug(entities) << "User attempted to edit an unknown entity. ID:" << entityItemID;
|
|
||||||
}
|
}
|
||||||
} else {
|
updateEntity(entityItemID, properties, senderNode);
|
||||||
|
existingEntity->markAsChangedOnServer();
|
||||||
|
} else if (packetType == PacketTypeEntityAdd) {
|
||||||
if (senderNode->getCanRez()) {
|
if (senderNode->getCanRez()) {
|
||||||
// this is a new entity... assign a new entityID
|
// this is a new entity... assign a new entityID
|
||||||
entityItemID = assignEntityID(entityItemID);
|
|
||||||
if (wantEditLogging()) {
|
if (wantEditLogging()) {
|
||||||
qCDebug(entities) << "User [" << senderNode->getUUID() << "] adding entity.";
|
qCDebug(entities) << "User [" << senderNode->getUUID() << "] adding entity.";
|
||||||
qCDebug(entities) << " properties:" << properties;
|
qCDebug(entities) << " properties:" << properties;
|
||||||
}
|
}
|
||||||
|
properties.setCreated(properties.getLastEdited());
|
||||||
EntityItem* newEntity = addEntity(entityItemID, properties);
|
EntityItem* newEntity = addEntity(entityItemID, properties);
|
||||||
if (newEntity) {
|
if (newEntity) {
|
||||||
newEntity->markAsChangedOnServer();
|
newEntity->markAsChangedOnServer();
|
||||||
|
@ -720,8 +600,11 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(entities) << "User without 'rez rights' [" << senderNode->getUUID() << "] attempted to add an entity.";
|
qCDebug(entities) << "User without 'rez rights' [" << senderNode->getUUID()
|
||||||
|
<< "] attempted to add an entity.";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qCDebug(entities) << "Add or Edit failed." << packetType << existingEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1026,66 +909,15 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons
|
||||||
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ {
|
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ {
|
||||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
||||||
EntityTreeElement* element = _entityToElementMap.value(entityItemID);
|
EntityTreeElement* element = _entityToElementMap.value(entityItemID);
|
||||||
if (!element && entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN){
|
|
||||||
// check the creator token version too...
|
|
||||||
EntityItemID creatorTokenOnly;
|
|
||||||
creatorTokenOnly.id = UNKNOWN_ENTITY_ID;
|
|
||||||
creatorTokenOnly.creatorTokenID = entityItemID.creatorTokenID;
|
|
||||||
creatorTokenOnly.isKnownID = false;
|
|
||||||
element = _entityToElementMap.value(creatorTokenOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we still didn't find the entity, but the ID was in our changed entityIDs, search for the new ID version
|
|
||||||
if (!element && _changedEntityIDs.contains(entityItemID)) {
|
|
||||||
element = getContainingElement(_changedEntityIDs[entityItemID]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
|
||||||
void EntityTree::resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
|
|
||||||
if (entityItemID.id == UNKNOWN_ENTITY_ID) {
|
|
||||||
//assert(entityItemID.id != UNKNOWN_ENTITY_ID);
|
|
||||||
qCDebug(entities) << "UNEXPECTED! resetContainingElement() called with UNKNOWN_ENTITY_ID. entityItemID:" << entityItemID;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (entityItemID.creatorTokenID == UNKNOWN_ENTITY_TOKEN) {
|
|
||||||
//assert(entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN);
|
|
||||||
qCDebug(entities) << "UNEXPECTED! resetContainingElement() called with UNKNOWN_ENTITY_TOKEN. entityItemID:" << entityItemID;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!element) {
|
|
||||||
//assert(element);
|
|
||||||
qCDebug(entities) << "UNEXPECTED! resetContainingElement() called with NULL element. entityItemID:" << entityItemID;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the old version with the creatorTokenID
|
|
||||||
EntityItemID creatorTokenVersion;
|
|
||||||
creatorTokenVersion.id = UNKNOWN_ENTITY_ID;
|
|
||||||
creatorTokenVersion.isKnownID = false;
|
|
||||||
creatorTokenVersion.creatorTokenID = entityItemID.creatorTokenID;
|
|
||||||
_entityToElementMap.remove(creatorTokenVersion);
|
|
||||||
|
|
||||||
// set the new version with both creator token and real ID
|
|
||||||
_entityToElementMap[entityItemID] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
|
void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
|
||||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
||||||
|
|
||||||
// If we're a sever side tree, we always remove the creator tokens from our map items
|
|
||||||
EntityItemID storedEntityItemID = entityItemID;
|
|
||||||
|
|
||||||
if (getIsServer()) {
|
|
||||||
storedEntityItemID.creatorTokenID = UNKNOWN_ENTITY_TOKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
_entityToElementMap[storedEntityItemID] = element;
|
_entityToElementMap[entityItemID] = element;
|
||||||
} else {
|
} else {
|
||||||
_entityToElementMap.remove(storedEntityItemID);
|
_entityToElementMap.remove(entityItemID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1174,14 +1006,14 @@ bool EntityTree::sendEntitiesOperation(OctreeElement* element, void* extraData)
|
||||||
|
|
||||||
const QList<EntityItem*>& entities = entityTreeElement->getEntities();
|
const QList<EntityItem*>& entities = entityTreeElement->getEntities();
|
||||||
for (int i = 0; i < entities.size(); i++) {
|
for (int i = 0; i < entities.size(); i++) {
|
||||||
EntityItemID newID(NEW_ENTITY, EntityItemID::getNextCreatorTokenID(), false);
|
EntityItemID newID(QUuid::createUuid());
|
||||||
args->newEntityIDs->append(newID);
|
args->newEntityIDs->append(newID);
|
||||||
EntityItemProperties properties = entities[i]->getProperties();
|
EntityItemProperties properties = entities[i]->getProperties();
|
||||||
properties.setPosition(properties.getPosition() + args->root);
|
properties.setPosition(properties.getPosition() + args->root);
|
||||||
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
|
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
|
||||||
|
|
||||||
// queue the packet to send to the server
|
// queue the packet to send to the server
|
||||||
args->packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, newID, properties);
|
args->packetSender->queueEditEntityMessage(PacketTypeEntityAdd, newID, properties);
|
||||||
|
|
||||||
// also update the local tree instantly (note: this is not our tree, but an alternate tree)
|
// also update the local tree instantly (note: this is not our tree, but an alternate tree)
|
||||||
if (args->localTree) {
|
if (args->localTree) {
|
||||||
|
@ -1226,7 +1058,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
|
||||||
|
|
||||||
EntityItem* entity = addEntity(entityItemID, properties);
|
EntityItem* entity = addEntity(entityItemID, properties);
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
qCDebug(entities) << "adding Entity failed:" << entityItemID << entity->getType();
|
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,6 @@ public:
|
||||||
|
|
||||||
int processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
int processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||||
int processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
int processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||||
void handleAddEntityResponse(const QByteArray& packet);
|
|
||||||
|
|
||||||
EntityItemFBXService* getFBXService() const { return _fbxService; }
|
EntityItemFBXService* getFBXService() const { return _fbxService; }
|
||||||
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
||||||
|
@ -148,7 +147,6 @@ public:
|
||||||
|
|
||||||
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/;
|
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/;
|
||||||
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||||
void resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
|
||||||
void debugDumpMap();
|
void debugDumpMap();
|
||||||
virtual void dumpTree();
|
virtual void dumpTree();
|
||||||
virtual void pruneTree();
|
virtual void pruneTree();
|
||||||
|
@ -198,7 +196,6 @@ private:
|
||||||
EntityItemFBXService* _fbxService;
|
EntityItemFBXService* _fbxService;
|
||||||
|
|
||||||
QHash<EntityItemID, EntityTreeElement*> _entityToElementMap;
|
QHash<EntityItemID, EntityTreeElement*> _entityToElementMap;
|
||||||
QHash<EntityItemID, EntityItemID> _changedEntityIDs;
|
|
||||||
|
|
||||||
EntitySimulation* _simulation;
|
EntitySimulation* _simulation;
|
||||||
|
|
||||||
|
|
|
@ -567,19 +567,6 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTreeElement::updateEntityItemID(const EntityItemID& creatorTokenEntityID, const EntityItemID& knownIDEntityID) {
|
|
||||||
uint16_t numberOfEntities = _entityItems->size();
|
|
||||||
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
|
||||||
EntityItem* thisEntity = (*_entityItems)[i];
|
|
||||||
|
|
||||||
EntityItemID thisEntityID = thisEntity->getEntityItemID();
|
|
||||||
|
|
||||||
if (thisEntityID == creatorTokenEntityID) {
|
|
||||||
thisEntity->setID(knownIDEntityID.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const {
|
const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const {
|
||||||
const EntityItem* closestEntity = NULL;
|
const EntityItem* closestEntity = NULL;
|
||||||
float closestEntityDistance = FLT_MAX;
|
float closestEntityDistance = FLT_MAX;
|
||||||
|
|
|
@ -151,9 +151,6 @@ public:
|
||||||
bool updateEntity(const EntityItem& entity);
|
bool updateEntity(const EntityItem& entity);
|
||||||
void addEntityItem(EntityItem* entity);
|
void addEntityItem(EntityItem* entity);
|
||||||
|
|
||||||
|
|
||||||
void updateEntityItemID(const EntityItemID& creatorTokenEntityID, const EntityItemID& knownIDEntityID);
|
|
||||||
|
|
||||||
const EntityItem* getClosestEntity(glm::vec3 position) const;
|
const EntityItem* getClosestEntity(glm::vec3 position) const;
|
||||||
|
|
||||||
/// finds all entities that touch a sphere
|
/// finds all entities that touch a sphere
|
||||||
|
|
|
@ -55,46 +55,46 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
||||||
static bool firstCall = true;
|
static bool firstCall = true;
|
||||||
if (firstCall) {
|
if (firstCall) {
|
||||||
NodeType::init();
|
NodeType::init();
|
||||||
|
|
||||||
// register the SharedNodePointer meta-type for signals/slots
|
// register the SharedNodePointer meta-type for signals/slots
|
||||||
qRegisterMetaType<SharedNodePointer>();
|
qRegisterMetaType<SharedNodePointer>();
|
||||||
firstCall = false;
|
firstCall = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
|
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
|
||||||
qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort();
|
qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort();
|
||||||
|
|
||||||
if (dtlsListenPort > 0) {
|
if (dtlsListenPort > 0) {
|
||||||
// only create the DTLS socket during constructor if a custom port is passed
|
// only create the DTLS socket during constructor if a custom port is passed
|
||||||
_dtlsSocket = new QUdpSocket(this);
|
_dtlsSocket = new QUdpSocket(this);
|
||||||
|
|
||||||
_dtlsSocket->bind(QHostAddress::AnyIPv4, dtlsListenPort);
|
_dtlsSocket->bind(QHostAddress::AnyIPv4, dtlsListenPort);
|
||||||
qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort();
|
qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int LARGER_BUFFER_SIZE = 1048576;
|
const int LARGER_BUFFER_SIZE = 1048576;
|
||||||
changeSocketBufferSizes(LARGER_BUFFER_SIZE);
|
changeSocketBufferSizes(LARGER_BUFFER_SIZE);
|
||||||
|
|
||||||
// check for local socket updates every so often
|
// check for local socket updates every so often
|
||||||
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
|
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
|
||||||
QTimer* localSocketUpdate = new QTimer(this);
|
QTimer* localSocketUpdate = new QTimer(this);
|
||||||
connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr);
|
connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr);
|
||||||
localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS);
|
localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS);
|
||||||
|
|
||||||
QTimer* silentNodeTimer = new QTimer(this);
|
QTimer* silentNodeTimer = new QTimer(this);
|
||||||
connect(silentNodeTimer, &QTimer::timeout, this, &LimitedNodeList::removeSilentNodes);
|
connect(silentNodeTimer, &QTimer::timeout, this, &LimitedNodeList::removeSilentNodes);
|
||||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
|
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
|
||||||
|
|
||||||
// check the local socket right now
|
// check the local socket right now
|
||||||
updateLocalSockAddr();
|
updateLocalSockAddr();
|
||||||
|
|
||||||
_packetStatTimer.start();
|
_packetStatTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
|
void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
|
||||||
QUuid oldUUID = _sessionUUID;
|
QUuid oldUUID = _sessionUUID;
|
||||||
_sessionUUID = sessionUUID;
|
_sessionUUID = sessionUUID;
|
||||||
|
|
||||||
if (sessionUUID != oldUUID) {
|
if (sessionUUID != oldUUID) {
|
||||||
qCDebug(networking) << "NodeList UUID changed from" << uuidStringWithoutCurlyBraces(oldUUID)
|
qCDebug(networking) << "NodeList UUID changed from" << uuidStringWithoutCurlyBraces(oldUUID)
|
||||||
<< "to" << uuidStringWithoutCurlyBraces(_sessionUUID);
|
<< "to" << uuidStringWithoutCurlyBraces(_sessionUUID);
|
||||||
|
@ -120,16 +120,16 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() {
|
||||||
if (!_dtlsSocket) {
|
if (!_dtlsSocket) {
|
||||||
// DTLS socket getter called but no DTLS socket exists, create it now
|
// DTLS socket getter called but no DTLS socket exists, create it now
|
||||||
_dtlsSocket = new QUdpSocket(this);
|
_dtlsSocket = new QUdpSocket(this);
|
||||||
|
|
||||||
_dtlsSocket->bind(QHostAddress::AnyIPv4, 0, QAbstractSocket::DontShareAddress);
|
_dtlsSocket->bind(QHostAddress::AnyIPv4, 0, QAbstractSocket::DontShareAddress);
|
||||||
|
|
||||||
// we're using DTLS and our socket is good to go, so make the required DTLS changes
|
// we're using DTLS and our socket is good to go, so make the required DTLS changes
|
||||||
// DTLS requires that IP_DONTFRAG be set
|
// DTLS requires that IP_DONTFRAG be set
|
||||||
// This is not accessible on some platforms (OS X) so we need to make sure DTLS still works without it
|
// This is not accessible on some platforms (OS X) so we need to make sure DTLS still works without it
|
||||||
|
|
||||||
qCDebug(networking) << "LimitedNodeList DTLS socket is listening on" << _dtlsSocket->localPort();
|
qCDebug(networking) << "LimitedNodeList DTLS socket is listening on" << _dtlsSocket->localPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return *_dtlsSocket;
|
return *_dtlsSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
bufferOpt = QAbstractSocket::SendBufferSizeSocketOption;
|
bufferOpt = QAbstractSocket::SendBufferSizeSocketOption;
|
||||||
bufferTypeString = "send";
|
bufferTypeString = "send";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption;
|
bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption;
|
||||||
bufferTypeString = "receive";
|
bufferTypeString = "receive";
|
||||||
|
@ -148,7 +148,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
||||||
int oldBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
|
int oldBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
|
||||||
if (oldBufferSize < numBytes) {
|
if (oldBufferSize < numBytes) {
|
||||||
int newBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
|
int newBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
|
||||||
|
|
||||||
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
|
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
|
||||||
<< newBufferSize << "bytes";
|
<< newBufferSize << "bytes";
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,13 +162,13 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
||||||
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||||
PacketType checkType = packetTypeForPacket(packet);
|
PacketType checkType = packetTypeForPacket(packet);
|
||||||
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
|
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
|
||||||
|
|
||||||
if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
|
if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
|
||||||
&& checkType != PacketTypeStunResponse) {
|
&& checkType != PacketTypeStunResponse) {
|
||||||
PacketType mismatchType = packetTypeForPacket(packet);
|
PacketType mismatchType = packetTypeForPacket(packet);
|
||||||
|
|
||||||
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
|
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
|
||||||
|
|
||||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||||
if (!versionDebugSuppressMap.contains(senderUUID, checkType)) {
|
if (!versionDebugSuppressMap.contains(senderUUID, checkType)) {
|
||||||
qCDebug(networking) << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender"
|
qCDebug(networking) << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender"
|
||||||
|
@ -176,13 +176,13 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||||
<< qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";
|
<< qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";
|
||||||
|
|
||||||
emit packetVersionMismatch();
|
emit packetVersionMismatch();
|
||||||
|
|
||||||
versionDebugSuppressMap.insert(senderUUID, checkType);
|
versionDebugSuppressMap.insert(senderUUID, checkType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NON_VERIFIED_PACKETS.contains(checkType)) {
|
if (!NON_VERIFIED_PACKETS.contains(checkType)) {
|
||||||
// figure out which node this is from
|
// figure out which node this is from
|
||||||
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
||||||
|
@ -192,26 +192,26 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;
|
static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;
|
||||||
|
|
||||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||||
if (!hashDebugSuppressMap.contains(senderUUID, checkType)) {
|
if (!hashDebugSuppressMap.contains(senderUUID, checkType)) {
|
||||||
qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender"
|
qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender"
|
||||||
<< uuidFromPacketHeader(packet);
|
<< uuidFromPacketHeader(packet);
|
||||||
|
|
||||||
hashDebugSuppressMap.insert(senderUUID, checkType);
|
hashDebugSuppressMap.insert(senderUUID, checkType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
static QString repeatedMessage
|
static QString repeatedMessage
|
||||||
= LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID");
|
= LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID");
|
||||||
|
|
||||||
qCDebug(networking) << "Packet of type" << checkType << "received from unknown node with UUID"
|
qCDebug(networking) << "Packet of type" << checkType << "received from unknown node with UUID"
|
||||||
<< qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
|
<< qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* a
|
||||||
} else {
|
} else {
|
||||||
emit dataReceived(NodeType::Unassigned, incomingPacket.size());
|
emit dataReceived(NodeType::Unassigned, incomingPacket.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,14 +235,14 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSock
|
||||||
// stat collection for packets
|
// stat collection for packets
|
||||||
++_numCollectedPackets;
|
++_numCollectedPackets;
|
||||||
_numCollectedBytes += datagram.size();
|
_numCollectedBytes += datagram.size();
|
||||||
|
|
||||||
qint64 bytesWritten = _nodeSocket.writeDatagram(datagram,
|
qint64 bytesWritten = _nodeSocket.writeDatagram(datagram,
|
||||||
destinationSockAddr.getAddress(), destinationSockAddr.getPort());
|
destinationSockAddr.getAddress(), destinationSockAddr.getPort());
|
||||||
|
|
||||||
if (bytesWritten < 0) {
|
if (bytesWritten < 0) {
|
||||||
qCDebug(networking) << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString();
|
qCDebug(networking) << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray datagramCopy = datagram;
|
QByteArray datagramCopy = datagram;
|
||||||
|
|
||||||
// if we're here and the connection secret is null, debug out - this could be a problem
|
// if we're here and the connection secret is null, debug out - this could be a problem
|
||||||
if (destinationNode->getConnectionSecret().isNull()) {
|
if (destinationNode->getConnectionSecret().isNull()) {
|
||||||
qDebug() << "LimitedNodeList::writeDatagram called for verified datagram with null connection secret for"
|
qDebug() << "LimitedNodeList::writeDatagram called for verified datagram with null connection secret for"
|
||||||
|
@ -278,21 +278,21 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform replacement of hash and optionally also sequence number in the header
|
// perform replacement of hash and optionally also sequence number in the header
|
||||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||||
PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
|
PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
|
||||||
replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(),
|
replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(),
|
||||||
sequenceNumber, packetType);
|
sequenceNumber, packetType);
|
||||||
} else {
|
} else {
|
||||||
replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType);
|
replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit dataSent(destinationNode->getType(), datagram.size());
|
emit dataSent(destinationNode->getType(), datagram.size());
|
||||||
auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr);
|
auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr);
|
||||||
// Keep track of per-destination-node bandwidth
|
// Keep track of per-destination-node bandwidth
|
||||||
destinationNode->recordBytesSent(bytesWritten);
|
destinationNode->recordBytesSent(bytesWritten);
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
// didn't have a destinationNode to send to, return 0
|
// didn't have a destinationNode to send to, return 0
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketType packetType = packetTypeForPacket(datagram);
|
PacketType packetType = packetTypeForPacket(datagram);
|
||||||
|
|
||||||
// optionally peform sequence number replacement in the header
|
// optionally peform sequence number replacement in the header
|
||||||
|
@ -328,7 +328,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons
|
||||||
return writeDatagram(datagram, *destinationSockAddr);
|
return writeDatagram(datagram, *destinationSockAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// didn't have a destinationNode to send to, return 0
|
// didn't have a destinationNode to send to, return 0
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -348,11 +348,11 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, c
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType) {
|
PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType) {
|
||||||
// Thanks to std::map and std::unordered_map this line either default constructs the
|
// Thanks to std::map and std::unordered_map this line either default constructs the
|
||||||
// PacketTypeSequenceMap and the PacketSequenceNumber or returns the existing value.
|
// PacketTypeSequenceMap and the PacketSequenceNumber or returns the existing value.
|
||||||
// We use the postfix increment so that the stored value is incremented and the next
|
// We use the postfix increment so that the stored value is incremented and the next
|
||||||
// return gives the correct value.
|
// return gives the correct value.
|
||||||
|
|
||||||
return _packetSequenceNumbers[nodeUUID][packetType]++;
|
return _packetSequenceNumbers[nodeUUID][packetType]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,21 +367,21 @@ void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const
|
||||||
|
|
||||||
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
|
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
|
||||||
QMutexLocker locker(&matchingNode->getMutex());
|
QMutexLocker locker(&matchingNode->getMutex());
|
||||||
|
|
||||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
|
||||||
// if this was a sequence numbered packet we should store the last seq number for
|
// if this was a sequence numbered packet we should store the last seq number for
|
||||||
// a packet of this type for this node
|
// a packet of this type for this node
|
||||||
PacketType packetType = packetTypeForPacket(packet);
|
PacketType packetType = packetTypeForPacket(packet);
|
||||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||||
matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType);
|
matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeData* linkedData = matchingNode->getLinkedData();
|
NodeData* linkedData = matchingNode->getLinkedData();
|
||||||
if (!linkedData && linkedDataCreateCallback) {
|
if (!linkedData && linkedDataCreateCallback) {
|
||||||
linkedDataCreateCallback(matchingNode.data());
|
linkedDataCreateCallback(matchingNode.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linkedData) {
|
if (linkedData) {
|
||||||
QMutexLocker linkedDataLocker(&linkedData->getMutex());
|
QMutexLocker linkedDataLocker(&linkedData->getMutex());
|
||||||
return linkedData->parseData(packet);
|
return linkedData->parseData(packet);
|
||||||
|
@ -391,42 +391,42 @@ int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& match
|
||||||
|
|
||||||
int LimitedNodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
int LimitedNodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
||||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||||
|
|
||||||
if (matchingNode) {
|
if (matchingNode) {
|
||||||
return updateNodeWithDataFromPacket(matchingNode, packet);
|
return updateNodeWithDataFromPacket(matchingNode, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we weren't able to match the sender address to the address we have for this node, unlock and don't parse
|
// we weren't able to match the sender address to the address we have for this node, unlock and don't parse
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||||
QReadLocker readLocker(&_nodeMutex);
|
QReadLocker readLocker(&_nodeMutex);
|
||||||
|
|
||||||
NodeHash::const_iterator it = _nodeHash.find(nodeUUID);
|
NodeHash::const_iterator it = _nodeHash.find(nodeUUID);
|
||||||
return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
|
return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedNodePointer LimitedNodeList::sendingNodeForPacket(const QByteArray& packet) {
|
SharedNodePointer LimitedNodeList::sendingNodeForPacket(const QByteArray& packet) {
|
||||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||||
|
|
||||||
// return the matching node, or NULL if there is no match
|
// return the matching node, or NULL if there is no match
|
||||||
return nodeWithUUID(nodeUUID);
|
return nodeWithUUID(nodeUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::eraseAllNodes() {
|
void LimitedNodeList::eraseAllNodes() {
|
||||||
qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list.";
|
qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list.";
|
||||||
|
|
||||||
QSet<SharedNodePointer> killedNodes;
|
QSet<SharedNodePointer> killedNodes;
|
||||||
eachNode([&killedNodes](const SharedNodePointer& node){
|
eachNode([&killedNodes](const SharedNodePointer& node){
|
||||||
killedNodes.insert(node);
|
killedNodes.insert(node);
|
||||||
});
|
});
|
||||||
|
|
||||||
// iterate the current nodes, emit that they are dying and remove them from the hash
|
// iterate the current nodes, emit that they are dying and remove them from the hash
|
||||||
_nodeMutex.lockForWrite();
|
_nodeMutex.lockForWrite();
|
||||||
_nodeHash.clear();
|
_nodeHash.clear();
|
||||||
_nodeMutex.unlock();
|
_nodeMutex.unlock();
|
||||||
|
|
||||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||||
handleNodeKill(killedNode);
|
handleNodeKill(killedNode);
|
||||||
}
|
}
|
||||||
|
@ -438,17 +438,17 @@ void LimitedNodeList::reset() {
|
||||||
|
|
||||||
void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
||||||
_nodeMutex.lockForRead();
|
_nodeMutex.lockForRead();
|
||||||
|
|
||||||
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
||||||
if (it != _nodeHash.end()) {
|
if (it != _nodeHash.end()) {
|
||||||
SharedNodePointer matchingNode = it->second;
|
SharedNodePointer matchingNode = it->second;
|
||||||
|
|
||||||
_nodeMutex.unlock();
|
_nodeMutex.unlock();
|
||||||
|
|
||||||
_nodeMutex.lockForWrite();
|
_nodeMutex.lockForWrite();
|
||||||
_nodeHash.unsafe_erase(it);
|
_nodeHash.unsafe_erase(it);
|
||||||
_nodeMutex.unlock();
|
_nodeMutex.unlock();
|
||||||
|
|
||||||
handleNodeKill(matchingNode);
|
handleNodeKill(matchingNode);
|
||||||
} else {
|
} else {
|
||||||
_nodeMutex.unlock();
|
_nodeMutex.unlock();
|
||||||
|
@ -472,34 +472,34 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
||||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||||
bool canAdjustLocks, bool canRez) {
|
bool canAdjustLocks, bool canRez) {
|
||||||
NodeHash::const_iterator it = _nodeHash.find(uuid);
|
NodeHash::const_iterator it = _nodeHash.find(uuid);
|
||||||
|
|
||||||
if (it != _nodeHash.end()) {
|
if (it != _nodeHash.end()) {
|
||||||
SharedNodePointer& matchingNode = it->second;
|
SharedNodePointer& matchingNode = it->second;
|
||||||
|
|
||||||
matchingNode->setPublicSocket(publicSocket);
|
matchingNode->setPublicSocket(publicSocket);
|
||||||
matchingNode->setLocalSocket(localSocket);
|
matchingNode->setLocalSocket(localSocket);
|
||||||
matchingNode->setCanAdjustLocks(canAdjustLocks);
|
matchingNode->setCanAdjustLocks(canAdjustLocks);
|
||||||
matchingNode->setCanRez(canRez);
|
matchingNode->setCanRez(canRez);
|
||||||
|
|
||||||
return matchingNode;
|
return matchingNode;
|
||||||
} else {
|
} else {
|
||||||
// we didn't have this node, so add them
|
// we didn't have this node, so add them
|
||||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks, canRez);
|
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks, canRez);
|
||||||
SharedNodePointer newNodePointer(newNode);
|
SharedNodePointer newNodePointer(newNode);
|
||||||
|
|
||||||
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));
|
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));
|
||||||
|
|
||||||
qCDebug(networking) << "Added" << *newNode;
|
qCDebug(networking) << "Added" << *newNode;
|
||||||
|
|
||||||
emit nodeAdded(newNodePointer);
|
emit nodeAdded(newNodePointer);
|
||||||
|
|
||||||
return newNodePointer;
|
return newNodePointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
|
|
||||||
eachNode([&](const SharedNodePointer& node){
|
eachNode([&](const SharedNodePointer& node){
|
||||||
if (destinationNodeTypes.contains(node->getType())) {
|
if (destinationNodeTypes.contains(node->getType())) {
|
||||||
writeDatagram(packet, node);
|
writeDatagram(packet, node);
|
||||||
|
@ -516,35 +516,35 @@ QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVeri
|
||||||
|
|
||||||
QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing,
|
QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing,
|
||||||
packetUUID);
|
packetUUID);
|
||||||
|
|
||||||
QDataStream packetStream(&pingPacket, QIODevice::Append);
|
QDataStream packetStream(&pingPacket, QIODevice::Append);
|
||||||
|
|
||||||
packetStream << pingType;
|
packetStream << pingType;
|
||||||
packetStream << usecTimestampNow();
|
packetStream << usecTimestampNow();
|
||||||
|
|
||||||
return pingPacket;
|
return pingPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) {
|
QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) {
|
||||||
QDataStream pingPacketStream(pingPacket);
|
QDataStream pingPacketStream(pingPacket);
|
||||||
pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
|
pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
|
||||||
|
|
||||||
PingType_t typeFromOriginalPing;
|
PingType_t typeFromOriginalPing;
|
||||||
pingPacketStream >> typeFromOriginalPing;
|
pingPacketStream >> typeFromOriginalPing;
|
||||||
|
|
||||||
quint64 timeFromOriginalPing;
|
quint64 timeFromOriginalPing;
|
||||||
pingPacketStream >> timeFromOriginalPing;
|
pingPacketStream >> timeFromOriginalPing;
|
||||||
|
|
||||||
PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing)
|
PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing)
|
||||||
? PacketTypePingReply : PacketTypeUnverifiedPingReply;
|
? PacketTypePingReply : PacketTypeUnverifiedPingReply;
|
||||||
|
|
||||||
QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID;
|
QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID;
|
||||||
|
|
||||||
QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetUUID);
|
QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetUUID);
|
||||||
QDataStream packetStream(&replyPacket, QIODevice::Append);
|
QDataStream packetStream(&replyPacket, QIODevice::Append);
|
||||||
|
|
||||||
packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow();
|
packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow();
|
||||||
|
|
||||||
return replyPacket;
|
return replyPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,9 +566,9 @@ void LimitedNodeList::resetPacketStats() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::removeSilentNodes() {
|
void LimitedNodeList::removeSilentNodes() {
|
||||||
|
|
||||||
QSet<SharedNodePointer> killedNodes;
|
QSet<SharedNodePointer> killedNodes;
|
||||||
|
|
||||||
eachNodeHashIterator([&](NodeHash::iterator& it){
|
eachNodeHashIterator([&](NodeHash::iterator& it){
|
||||||
SharedNodePointer node = it->second;
|
SharedNodePointer node = it->second;
|
||||||
node->getMutex().lock();
|
node->getMutex().lock();
|
||||||
|
@ -582,10 +582,10 @@ void LimitedNodeList::removeSilentNodes() {
|
||||||
// we didn't erase this node, push the iterator forwards
|
// we didn't erase this node, push the iterator forwards
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->getMutex().unlock();
|
node->getMutex().unlock();
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||||
handleNodeKill(killedNode);
|
handleNodeKill(killedNode);
|
||||||
}
|
}
|
||||||
|
@ -595,38 +595,38 @@ const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
||||||
const int NUM_BYTES_STUN_HEADER = 20;
|
const int NUM_BYTES_STUN_HEADER = 20;
|
||||||
|
|
||||||
void LimitedNodeList::sendSTUNRequest() {
|
void LimitedNodeList::sendSTUNRequest() {
|
||||||
|
|
||||||
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
||||||
|
|
||||||
int packetIndex = 0;
|
int packetIndex = 0;
|
||||||
|
|
||||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||||
|
|
||||||
// leading zeros + message type
|
// leading zeros + message type
|
||||||
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
||||||
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
||||||
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
||||||
|
|
||||||
// message length (no additional attributes are included)
|
// message length (no additional attributes are included)
|
||||||
uint16_t messageLength = 0;
|
uint16_t messageLength = 0;
|
||||||
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
||||||
packetIndex += sizeof(messageLength);
|
packetIndex += sizeof(messageLength);
|
||||||
|
|
||||||
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
||||||
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||||
|
|
||||||
// transaction ID (random 12-byte unsigned integer)
|
// transaction ID (random 12-byte unsigned integer)
|
||||||
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||||
QUuid randomUUID = QUuid::createUuid();
|
QUuid randomUUID = QUuid::createUuid();
|
||||||
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
||||||
|
|
||||||
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
|
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
|
||||||
_stunSockAddr.getAddress(), _stunSockAddr.getPort());
|
_stunSockAddr.getAddress(), _stunSockAddr.getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::rebindNodeSocket() {
|
void LimitedNodeList::rebindNodeSocket() {
|
||||||
quint16 oldPort = _nodeSocket.localPort();
|
quint16 oldPort = _nodeSocket.localPort();
|
||||||
|
|
||||||
_nodeSocket.close();
|
_nodeSocket.close();
|
||||||
_nodeSocket.bind(QHostAddress::AnyIPv4, oldPort);
|
_nodeSocket.bind(QHostAddress::AnyIPv4, oldPort);
|
||||||
}
|
}
|
||||||
|
@ -636,125 +636,125 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
||||||
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
|
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
|
||||||
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
||||||
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
|
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
|
||||||
|
|
||||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||||
|
|
||||||
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
||||||
|
|
||||||
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
||||||
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
||||||
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
||||||
|
|
||||||
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
||||||
while (attributeStartIndex < packet.size()) {
|
while (attributeStartIndex < packet.size()) {
|
||||||
if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
||||||
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
||||||
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
||||||
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
||||||
|
|
||||||
uint8_t addressFamily = 0;
|
uint8_t addressFamily = 0;
|
||||||
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
|
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
|
||||||
|
|
||||||
byteIndex += sizeof(addressFamily);
|
byteIndex += sizeof(addressFamily);
|
||||||
|
|
||||||
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
||||||
// grab the X-Port
|
// grab the X-Port
|
||||||
uint16_t xorMappedPort = 0;
|
uint16_t xorMappedPort = 0;
|
||||||
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
|
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
|
||||||
|
|
||||||
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
||||||
|
|
||||||
byteIndex += sizeof(xorMappedPort);
|
byteIndex += sizeof(xorMappedPort);
|
||||||
|
|
||||||
// grab the X-Address
|
// grab the X-Address
|
||||||
uint32_t xorMappedAddress = 0;
|
uint32_t xorMappedAddress = 0;
|
||||||
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
|
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
|
||||||
|
|
||||||
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||||
|
|
||||||
QHostAddress newPublicAddress = QHostAddress(stunAddress);
|
QHostAddress newPublicAddress = QHostAddress(stunAddress);
|
||||||
|
|
||||||
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
|
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
|
||||||
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
||||||
|
|
||||||
qCDebug(networking, "New public socket received from STUN server is %s:%hu",
|
qCDebug(networking, "New public socket received from STUN server is %s:%hu",
|
||||||
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
||||||
_publicSockAddr.getPort());
|
_publicSockAddr.getPort());
|
||||||
|
|
||||||
emit publicSockAddrChanged(_publicSockAddr);
|
emit publicSockAddrChanged(_publicSockAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// push forward attributeStartIndex by the length of this attribute
|
// push forward attributeStartIndex by the length of this attribute
|
||||||
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
||||||
|
|
||||||
uint16_t attributeLength = 0;
|
uint16_t attributeLength = 0;
|
||||||
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
||||||
sizeof(attributeLength));
|
sizeof(attributeLength));
|
||||||
attributeLength = ntohs(attributeLength);
|
attributeLength = ntohs(attributeLength);
|
||||||
|
|
||||||
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
|
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::updateLocalSockAddr() {
|
void LimitedNodeList::updateLocalSockAddr() {
|
||||||
HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort());
|
HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort());
|
||||||
if (newSockAddr != _localSockAddr) {
|
if (newSockAddr != _localSockAddr) {
|
||||||
|
|
||||||
if (_localSockAddr.isNull()) {
|
if (_localSockAddr.isNull()) {
|
||||||
qCDebug(networking) << "Local socket is" << newSockAddr;
|
qCDebug(networking) << "Local socket is" << newSockAddr;
|
||||||
} else {
|
} else {
|
||||||
qCDebug(networking) << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr;
|
qCDebug(networking) << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_localSockAddr = newSockAddr;
|
_localSockAddr = newSockAddr;
|
||||||
|
|
||||||
emit localSockAddrChanged(_localSockAddr);
|
emit localSockAddrChanged(_localSockAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
|
void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
|
||||||
QUuid headerID, const QUuid& connectionRequestID) {
|
QUuid headerID, const QUuid& connectionRequestID) {
|
||||||
|
|
||||||
if (headerID.isNull()) {
|
if (headerID.isNull()) {
|
||||||
headerID = _sessionUUID;
|
headerID = _sessionUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray iceRequestByteArray = byteArrayWithUUIDPopulatedHeader(PacketTypeIceServerHeartbeat, headerID);
|
QByteArray iceRequestByteArray = byteArrayWithUUIDPopulatedHeader(PacketTypeIceServerHeartbeat, headerID);
|
||||||
QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append);
|
QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append);
|
||||||
|
|
||||||
iceDataStream << _publicSockAddr << _localSockAddr;
|
iceDataStream << _publicSockAddr << _localSockAddr;
|
||||||
|
|
||||||
if (!connectionRequestID.isNull()) {
|
if (!connectionRequestID.isNull()) {
|
||||||
iceDataStream << connectionRequestID;
|
iceDataStream << connectionRequestID;
|
||||||
|
|
||||||
qCDebug(networking) << "Sending packet to ICE server to request connection info for peer with ID"
|
qCDebug(networking) << "Sending packet to ICE server to request connection info for peer with ID"
|
||||||
<< uuidStringWithoutCurlyBraces(connectionRequestID);
|
<< uuidStringWithoutCurlyBraces(connectionRequestID);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr);
|
writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort) {
|
void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort) {
|
||||||
// save our local port to shared memory so that assignment client children know how to talk to this parent
|
// save our local port to shared memory so that assignment client children know how to talk to this parent
|
||||||
QSharedMemory* sharedPortMem = new QSharedMemory(key, parent);
|
QSharedMemory* sharedPortMem = new QSharedMemory(key, parent);
|
||||||
|
|
||||||
// attempt to create the shared memory segment
|
// attempt to create the shared memory segment
|
||||||
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
|
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
|
||||||
sharedPortMem->lock();
|
sharedPortMem->lock();
|
||||||
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
|
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
|
||||||
sharedPortMem->unlock();
|
sharedPortMem->unlock();
|
||||||
|
|
||||||
qCDebug(networking) << "Wrote local listening port" << localPort << "to shared memory at key" << key;
|
qCDebug(networking) << "Wrote local listening port" << localPort << "to shared memory at key" << key;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
|
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
|
||||||
|
@ -762,22 +762,15 @@ void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LimitedNodeList::getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem,
|
bool LimitedNodeList::getLocalServerPortFromSharedMemory(const QString key, quint16& localPort) {
|
||||||
quint16& localPort) {
|
QSharedMemory sharedMem(key);
|
||||||
if (!sharedMem) {
|
if (!sharedMem.attach(QSharedMemory::ReadOnly)) {
|
||||||
sharedMem = new QSharedMemory(key, this);
|
qWarning() << "Could not attach to shared memory at key" << key;
|
||||||
|
return false;
|
||||||
if (!sharedMem->attach(QSharedMemory::ReadOnly)) {
|
} else {
|
||||||
qWarning() << "Could not attach to shared memory at key" << key;
|
sharedMem.lock();
|
||||||
}
|
memcpy(&localPort, sharedMem.data(), sizeof(localPort));
|
||||||
}
|
sharedMem.unlock();
|
||||||
|
|
||||||
if (sharedMem->isAttached()) {
|
|
||||||
sharedMem->lock();
|
|
||||||
memcpy(&localPort, sharedMem->data(), sizeof(localPort));
|
|
||||||
sharedMem->unlock();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace PingType {
|
||||||
class LimitedNodeList : public QObject, public Dependency {
|
class LimitedNodeList : public QObject, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const QUuid& getSessionUUID() const { return _sessionUUID; }
|
const QUuid& getSessionUUID() const { return _sessionUUID; }
|
||||||
void setSessionUUID(const QUuid& sessionUUID);
|
void setSessionUUID(const QUuid& sessionUUID);
|
||||||
|
@ -89,22 +89,22 @@ public:
|
||||||
|
|
||||||
bool getThisNodeCanRez() const { return _thisNodeCanRez; }
|
bool getThisNodeCanRez() const { return _thisNodeCanRez; }
|
||||||
void setThisNodeCanRez(bool canRez);
|
void setThisNodeCanRez(bool canRez);
|
||||||
|
|
||||||
void rebindNodeSocket();
|
void rebindNodeSocket();
|
||||||
QUdpSocket& getNodeSocket() { return _nodeSocket; }
|
QUdpSocket& getNodeSocket() { return _nodeSocket; }
|
||||||
QUdpSocket& getDTLSSocket();
|
QUdpSocket& getDTLSSocket();
|
||||||
|
|
||||||
bool packetVersionAndHashMatch(const QByteArray& packet);
|
bool packetVersionAndHashMatch(const QByteArray& packet);
|
||||||
|
|
||||||
QByteArray byteArrayWithPopulatedHeader(PacketType packetType)
|
QByteArray byteArrayWithPopulatedHeader(PacketType packetType)
|
||||||
{ return byteArrayWithUUIDPopulatedHeader(packetType, _sessionUUID); }
|
{ return byteArrayWithUUIDPopulatedHeader(packetType, _sessionUUID); }
|
||||||
int populatePacketHeader(QByteArray& packet, PacketType packetType)
|
int populatePacketHeader(QByteArray& packet, PacketType packetType)
|
||||||
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
|
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
|
||||||
int populatePacketHeader(char* packet, PacketType packetType)
|
int populatePacketHeader(char* packet, PacketType packetType)
|
||||||
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
|
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
|
||||||
|
|
||||||
qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port);
|
qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port);
|
||||||
|
|
||||||
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
||||||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||||
|
|
||||||
|
@ -120,16 +120,16 @@ public:
|
||||||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||||
|
|
||||||
void (*linkedDataCreateCallback)(Node *);
|
void (*linkedDataCreateCallback)(Node *);
|
||||||
|
|
||||||
int size() const { return _nodeHash.size(); }
|
int size() const { return _nodeHash.size(); }
|
||||||
|
|
||||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||||
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
||||||
|
|
||||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
||||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||||
bool canAdjustLocks, bool canRez);
|
bool canAdjustLocks, bool canRez);
|
||||||
|
|
||||||
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
|
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
|
||||||
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
|
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
|
||||||
|
|
||||||
|
@ -144,21 +144,21 @@ public:
|
||||||
|
|
||||||
void getPacketStats(float &packetsPerSecond, float &bytesPerSecond);
|
void getPacketStats(float &packetsPerSecond, float &bytesPerSecond);
|
||||||
void resetPacketStats();
|
void resetPacketStats();
|
||||||
|
|
||||||
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true,
|
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true,
|
||||||
const QUuid& packetHeaderID = QUuid());
|
const QUuid& packetHeaderID = QUuid());
|
||||||
QByteArray constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID = QUuid());
|
QByteArray constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID = QUuid());
|
||||||
|
|
||||||
virtual void sendSTUNRequest();
|
virtual void sendSTUNRequest();
|
||||||
virtual bool processSTUNResponse(const QByteArray& packet);
|
virtual bool processSTUNResponse(const QByteArray& packet);
|
||||||
|
|
||||||
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
|
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
|
||||||
QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid());
|
QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid());
|
||||||
|
|
||||||
template<typename NodeLambda>
|
template<typename NodeLambda>
|
||||||
void eachNode(NodeLambda functor) {
|
void eachNode(NodeLambda functor) {
|
||||||
QReadLocker readLock(&_nodeMutex);
|
QReadLocker readLock(&_nodeMutex);
|
||||||
|
|
||||||
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
||||||
functor(it->second);
|
functor(it->second);
|
||||||
}
|
}
|
||||||
|
@ -178,44 +178,44 @@ public:
|
||||||
template<typename BreakableNodeLambda>
|
template<typename BreakableNodeLambda>
|
||||||
void eachNodeBreakable(BreakableNodeLambda functor) {
|
void eachNodeBreakable(BreakableNodeLambda functor) {
|
||||||
QReadLocker readLock(&_nodeMutex);
|
QReadLocker readLock(&_nodeMutex);
|
||||||
|
|
||||||
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
||||||
if (!functor(it->second)) {
|
if (!functor(it->second)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PredLambda>
|
template<typename PredLambda>
|
||||||
SharedNodePointer nodeMatchingPredicate(const PredLambda predicate) {
|
SharedNodePointer nodeMatchingPredicate(const PredLambda predicate) {
|
||||||
QReadLocker readLock(&_nodeMutex);
|
QReadLocker readLock(&_nodeMutex);
|
||||||
|
|
||||||
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
||||||
if (predicate(it->second)) {
|
if (predicate(it->second)) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SharedNodePointer();
|
return SharedNodePointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort);
|
void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort);
|
||||||
bool getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem, quint16& localPort);
|
bool getLocalServerPortFromSharedMemory(const QString key, quint16& localPort);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void eraseAllNodes();
|
void eraseAllNodes();
|
||||||
|
|
||||||
void removeSilentNodes();
|
void removeSilentNodes();
|
||||||
|
|
||||||
void updateLocalSockAddr();
|
void updateLocalSockAddr();
|
||||||
|
|
||||||
void killNodeWithUUID(const QUuid& nodeUUID);
|
void killNodeWithUUID(const QUuid& nodeUUID);
|
||||||
signals:
|
signals:
|
||||||
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
||||||
void nodeAdded(SharedNodePointer);
|
void nodeAdded(SharedNodePointer);
|
||||||
void nodeKilled(SharedNodePointer);
|
void nodeKilled(SharedNodePointer);
|
||||||
|
|
||||||
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
|
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
|
||||||
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
|
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
|
||||||
|
|
||||||
|
@ -226,18 +226,18 @@ signals:
|
||||||
void dataReceived(const quint8 channel_type, const int bytes);
|
void dataReceived(const quint8 channel_type, const int bytes);
|
||||||
|
|
||||||
void packetVersionMismatch();
|
void packetVersionMismatch();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
|
LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
|
||||||
LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||||
void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||||
|
|
||||||
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr);
|
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr);
|
||||||
|
|
||||||
PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType);
|
PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType);
|
||||||
|
|
||||||
void changeSocketBufferSizes(int numBytes);
|
void changeSocketBufferSizes(int numBytes);
|
||||||
|
|
||||||
void handleNodeKill(const SharedNodePointer& node);
|
void handleNodeKill(const SharedNodePointer& node);
|
||||||
|
|
||||||
QUuid _sessionUUID;
|
QUuid _sessionUUID;
|
||||||
|
@ -258,17 +258,17 @@ protected:
|
||||||
bool _thisNodeCanRez;
|
bool _thisNodeCanRez;
|
||||||
|
|
||||||
std::unordered_map<QUuid, PacketTypeSequenceMap, UUIDHasher> _packetSequenceNumbers;
|
std::unordered_map<QUuid, PacketTypeSequenceMap, UUIDHasher> _packetSequenceNumbers;
|
||||||
|
|
||||||
template<typename IteratorLambda>
|
template<typename IteratorLambda>
|
||||||
void eachNodeHashIterator(IteratorLambda functor) {
|
void eachNodeHashIterator(IteratorLambda functor) {
|
||||||
QWriteLocker writeLock(&_nodeMutex);
|
QWriteLocker writeLock(&_nodeMutex);
|
||||||
NodeHash::iterator it = _nodeHash.begin();
|
NodeHash::iterator it = _nodeHash.begin();
|
||||||
|
|
||||||
while (it != _nodeHash.end()) {
|
while (it != _nodeHash.end()) {
|
||||||
functor(it);
|
functor(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_LimitedNodeList_h
|
#endif // hifi_LimitedNodeList_h
|
||||||
|
|
|
@ -335,12 +335,8 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost
|
if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost
|
||||||
|| _domainHandler.getHostname() == "localhost") {
|
|| _domainHandler.getHostname() == "localhost") {
|
||||||
|
|
||||||
static QSharedMemory* localDSPortSharedMem = NULL;
|
|
||||||
|
|
||||||
quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT;
|
quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY,
|
getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, domainPort);
|
||||||
localDSPortSharedMem,
|
|
||||||
domainPort);
|
|
||||||
qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort;
|
qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort;
|
||||||
_domainHandler.setPort(domainPort);
|
_domainHandler.setPort(domainPort);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,10 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeStopNode:
|
case PacketTypeStopNode:
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeEntityAddOrEdit:
|
case PacketTypeEntityAdd:
|
||||||
|
case PacketTypeEntityEdit:
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
return VERSION_ENTITIES_HAVE_FRICTION;
|
return VERSION_NO_ENTITY_ID_SWAP;
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
return 2;
|
return 2;
|
||||||
case PacketTypeAudioStreamStats:
|
case PacketTypeAudioStreamStats:
|
||||||
|
@ -117,9 +118,7 @@ QString nameForPacketType(PacketType packetType) {
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeNodeJsonStats);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeNodeJsonStats);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityQuery);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityQuery);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityData);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityData);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddOrEdit);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
|
||||||
|
@ -129,6 +128,8 @@ QString nameForPacketType(PacketType packetType) {
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
|
||||||
|
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
|
||||||
default:
|
default:
|
||||||
return QString("Type: ") + QString::number((int)packetType);
|
return QString("Type: ") + QString::number((int)packetType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,9 +68,9 @@ enum PacketType {
|
||||||
PacketTypeNodeJsonStats,
|
PacketTypeNodeJsonStats,
|
||||||
PacketTypeEntityQuery, // 40
|
PacketTypeEntityQuery, // 40
|
||||||
PacketTypeEntityData,
|
PacketTypeEntityData,
|
||||||
PacketTypeEntityAddOrEdit,
|
PacketTypeEntityAdd,
|
||||||
PacketTypeEntityErase,
|
PacketTypeEntityErase,
|
||||||
PacketTypeEntityAddResponse,
|
PacketTypeEntityEdit,
|
||||||
PacketTypeOctreeDataNack, // 45
|
PacketTypeOctreeDataNack, // 45
|
||||||
PacketTypeStopNode,
|
PacketTypeStopNode,
|
||||||
PacketTypeAudioEnvironment,
|
PacketTypeAudioEnvironment,
|
||||||
|
@ -178,5 +178,6 @@ const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23;
|
||||||
const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24;
|
const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24;
|
||||||
const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
|
const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
|
||||||
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
|
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
|
||||||
|
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -334,7 +334,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
|
||||||
|
|
||||||
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
|
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
assert(_entity->isKnownID());
|
|
||||||
|
|
||||||
bool active = _body->isActive();
|
bool active = _body->isActive();
|
||||||
if (!active) {
|
if (!active) {
|
||||||
|
@ -434,7 +433,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
||||||
qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()...";
|
qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()...";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties);
|
entityPacketSender->queueEditEntityMessage(PacketTypeEntityEdit, id, properties);
|
||||||
_entity->setLastBroadcast(usecTimestampNow());
|
_entity->setLastBroadcast(usecTimestampNow());
|
||||||
} else {
|
} else {
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
|
|
|
@ -196,7 +196,7 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio
|
||||||
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
|
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
|
||||||
EntityItem* entity = entityState->getEntity();
|
EntityItem* entity = entityState->getEntity();
|
||||||
if (entity) {
|
if (entity) {
|
||||||
if (entity->isKnownID() && entityState->isCandidateForOwnership(sessionID)) {
|
if (entityState->isCandidateForOwnership(sessionID)) {
|
||||||
_outgoingChanges.insert(entityState);
|
_outgoingChanges.insert(entityState);
|
||||||
}
|
}
|
||||||
_entitiesToSort.insert(entityState->getEntity());
|
_entitiesToSort.insert(entityState->getEntity());
|
||||||
|
|
|
@ -321,7 +321,8 @@ void ScriptEngine::init() {
|
||||||
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
|
qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue);
|
||||||
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
|
qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
|
||||||
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
|
qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
|
||||||
qScriptRegisterSequenceMetaType<QVector<EntityItemID> >(this);
|
qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
|
||||||
|
qScriptRegisterSequenceMetaType<QVector<EntityItemID>>(this);
|
||||||
|
|
||||||
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);
|
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);
|
||||||
qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);
|
qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);
|
||||||
|
|
|
@ -159,16 +159,17 @@ void HifiConfigVariantMap::addMissingValuesToExistingMap(QVariantMap& existingMa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath) {
|
QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath, bool shouldCreateIfMissing) {
|
||||||
int dotIndex = keyPath.indexOf('.');
|
int dotIndex = keyPath.indexOf('.');
|
||||||
|
|
||||||
QString firstKey = (dotIndex == -1) ? keyPath : keyPath.mid(0, dotIndex);
|
QString firstKey = (dotIndex == -1) ? keyPath : keyPath.mid(0, dotIndex);
|
||||||
|
|
||||||
if (variantMap.contains(firstKey)) {
|
if (shouldCreateIfMissing || variantMap.contains(firstKey)) {
|
||||||
if (dotIndex == -1) {
|
if (dotIndex == -1) {
|
||||||
return &variantMap[firstKey];
|
return &variantMap[firstKey];
|
||||||
} else if (variantMap[firstKey].canConvert(QMetaType::QVariantMap)) {
|
} else if (variantMap[firstKey].canConvert(QMetaType::QVariantMap)) {
|
||||||
return valueForKeyPath(*static_cast<QVariantMap*>(variantMap[firstKey].data()), keyPath.mid(dotIndex + 1));
|
return valueForKeyPath(*static_cast<QVariantMap*>(variantMap[firstKey].data()), keyPath.mid(dotIndex + 1),
|
||||||
|
shouldCreateIfMissing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,6 @@ private:
|
||||||
void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap);
|
void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap);
|
||||||
};
|
};
|
||||||
|
|
||||||
QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath);
|
QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath, bool shouldCreateIfMissing = false);
|
||||||
|
|
||||||
#endif // hifi_HifiConfigVariantMap_h
|
#endif // hifi_HifiConfigVariantMap_h
|
||||||
|
|
|
@ -200,11 +200,18 @@ void collisionFromScriptValue(const QScriptValue &object, Collision& collision)
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue quuidToScriptValue(QScriptEngine* engine, const QUuid& uuid) {
|
QScriptValue quuidToScriptValue(QScriptEngine* engine, const QUuid& uuid) {
|
||||||
|
if (uuid.isNull()) {
|
||||||
|
return QScriptValue::NullValue;
|
||||||
|
}
|
||||||
QScriptValue obj(uuid.toString());
|
QScriptValue obj(uuid.toString());
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid) {
|
void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid) {
|
||||||
|
if (object.isNull()) {
|
||||||
|
uuid = QUuid();
|
||||||
|
return;
|
||||||
|
}
|
||||||
QString uuidAsString = object.toVariant().toString();
|
QString uuidAsString = object.toVariant().toString();
|
||||||
QUuid fromString(uuidAsString);
|
QUuid fromString(uuidAsString);
|
||||||
uuid = fromString;
|
uuid = fromString;
|
||||||
|
|
|
@ -42,7 +42,6 @@ void EntityTests::entityTreeTests(bool verbose) {
|
||||||
EntityTree tree;
|
EntityTree tree;
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
EntityItemID entityID(id);
|
EntityItemID entityID(id);
|
||||||
entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs
|
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
float oneMeter = 1.0f;
|
float oneMeter = 1.0f;
|
||||||
float halfOfDomain = TREE_SCALE * 0.5f;
|
float halfOfDomain = TREE_SCALE * 0.5f;
|
||||||
|
@ -90,8 +89,6 @@ void EntityTests::entityTreeTests(bool verbose) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entityID.isKnownID = true; // this is a temporary workaround to allow local tree entities to be added with known IDs
|
|
||||||
|
|
||||||
{
|
{
|
||||||
testsTaken++;
|
testsTaken++;
|
||||||
QString testName = "change position of entity in tree";
|
QString testName = "change position of entity in tree";
|
||||||
|
@ -253,7 +250,6 @@ void EntityTests::entityTreeTests(bool verbose) {
|
||||||
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
||||||
QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
|
QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
|
||||||
EntityItemID entityID(id);
|
EntityItemID entityID(id);
|
||||||
entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs
|
|
||||||
|
|
||||||
float randomX = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
|
float randomX = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
|
||||||
float randomY = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
|
float randomY = randFloatInRange(1.0f ,(float)TREE_SCALE - 1.0f);
|
||||||
|
@ -357,7 +353,6 @@ void EntityTests::entityTreeTests(bool verbose) {
|
||||||
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
||||||
QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
|
QUuid id = QUuid::createUuid();// make sure it doesn't collide with previous entity ids
|
||||||
EntityItemID entityID(id);
|
EntityItemID entityID(id);
|
||||||
entityID.isKnownID = true; // this is a temporary workaround to allow local tree entities to be added with known IDs
|
|
||||||
|
|
||||||
if (extraVerbose) {
|
if (extraVerbose) {
|
||||||
qDebug() << "before:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
|
qDebug() << "before:" << i << "getOctreeElementsCount()=" << tree.getOctreeElementsCount();
|
||||||
|
|
Loading…
Reference in a new issue