Merge branch 'master' of github.com:highfidelity/hifi into fix-edit-js-restart

This commit is contained in:
Seth Alves 2016-05-23 09:58:20 -07:00
commit 00336f4860
126 changed files with 1920 additions and 1342 deletions

View file

@ -51,6 +51,8 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
LogUtils::init();
QSettings::setDefaultFormat(QSettings::IniFormat);
DependencyManager::set<AccountManager>();
auto scriptableAvatar = DependencyManager::set<ScriptableAvatar>();
auto addressManager = DependencyManager::set<AddressManager>();
@ -116,7 +118,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
// connections to AccountManager for authentication
connect(&AccountManager::getInstance(), &AccountManager::authRequired,
connect(DependencyManager::get<AccountManager>().data(), &AccountManager::authRequired,
this, &AssignmentClient::handleAuthenticationRequest);
// Create Singleton objects on main thread
@ -309,13 +311,13 @@ void AssignmentClient::handleAuthenticationRequest() {
QString username = sysEnvironment.value(DATA_SERVER_USERNAME_ENV);
QString password = sysEnvironment.value(DATA_SERVER_PASSWORD_ENV);
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (!username.isEmpty() && !password.isEmpty()) {
// ask the account manager to log us in from the env variables
accountManager.requestAccessToken(username, password);
accountManager->requestAccessToken(username, password);
} else {
qCWarning(assigmnentclient) << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString())
qCWarning(assigmnentclient) << "Authentication was requested against" << qPrintable(accountManager->getAuthURL().toString())
<< "but both or one of" << qPrintable(DATA_SERVER_USERNAME_ENV)
<< "/" << qPrintable(DATA_SERVER_PASSWORD_ENV) << "are not set. Unable to authenticate.";

View file

@ -60,8 +60,8 @@ public:
virtual void trackViewerGone(const QUuid& sessionID) override;
public slots:
virtual void nodeAdded(SharedNodePointer node);
virtual void nodeKilled(SharedNodePointer node);
virtual void nodeAdded(SharedNodePointer node) override;
virtual void nodeKilled(SharedNodePointer node) override;
void pruneDeletedEntities();
protected:

View file

@ -55,9 +55,9 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
if (message->getSize() == 0) {
return;
}
QDataStream packetStream(message->getMessage());
// read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it
NodeConnectionData nodeConnection = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr());
@ -105,6 +105,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
nodeData->setSendingSockAddr(message->getSenderSockAddr());
nodeData->setNodeInterestSet(nodeConnection.interestList.toSet());
nodeData->setPlaceName(nodeConnection.placeName);
// signal that we just connected a node so the DomainServer can get it a list
// and broadcast its presence right away
@ -150,6 +151,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
nodeData->setAssignmentUUID(matchingQueuedAssignment->getUUID());
nodeData->setWalletUUID(it->second.getWalletUUID());
nodeData->setNodeVersion(it->second.getNodeVersion());
nodeData->setWasAssigned(true);
// cleanup the PendingAssignedNodeData for this assignment now that it's connecting
_pendingAssignedNodes.erase(it);
@ -282,7 +284,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
// set the edit rights for this user
newNode->setIsAllowedEditor(isAllowedEditor);
newNode->setCanRez(canRez);
// grab the linked data for our new node so we can set the username
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(newNode->getLinkedData());
@ -485,7 +487,7 @@ void DomainGatekeeper::requestUserPublicKey(const QString& username) {
qDebug() << "Requesting public key for user" << username;
AccountManager::getInstance().sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
DependencyManager::get<AccountManager>()->sendRequest(USER_PUBLIC_KEY_PATH.arg(username),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation, callbackParams);
}

View file

@ -26,6 +26,7 @@
#include <AccountManager.h>
#include <BuildInfo.h>
#include <DependencyManager.h>
#include <HifiConfigVariantMap.h>
#include <HTTPConnection.h>
#include <LogUtils.h>
@ -77,7 +78,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
// make sure we have a fresh AccountManager instance
// (need this since domain-server can restart itself and maintain static variables)
AccountManager::getInstance(true);
DependencyManager::set<AccountManager>();
auto args = arguments();
@ -195,8 +196,8 @@ bool DomainServer::optionallySetupOAuth() {
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL;
}
AccountManager& accountManager = AccountManager::getInstance();
accountManager.setAuthURL(_oauthProviderURL);
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->setAuthURL(_oauthProviderURL);
_oauthClientID = settingsMap.value(OAUTH_CLIENT_ID_OPTION).toString();
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
@ -239,7 +240,7 @@ void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) {
// we've been asked to grab a temporary name from the API
// so fire off that request now
auto& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
// get callbacks for temporary domain result
JSONCallbackParameters callbackParameters;
@ -248,8 +249,8 @@ void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) {
callbackParameters.errorCallbackReceiver = this;
callbackParameters.errorCallbackMethod = "handleTempDomainError";
accountManager.sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, callbackParameters);
accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None,
QNetworkAccessManager::PostOperation, callbackParameters);
}
}
@ -397,7 +398,7 @@ bool DomainServer::resetAccountManagerAccessToken() {
<< "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN";
// clear any existing access token from AccountManager
AccountManager::getInstance().setAccessTokenForCurrentAuthURL(QString());
DependencyManager::get<AccountManager>()->setAccessTokenForCurrentAuthURL(QString());
return false;
}
@ -407,7 +408,7 @@ bool DomainServer::resetAccountManagerAccessToken() {
}
// give this access token to the AccountManager
AccountManager::getInstance().setAccessTokenForCurrentAuthURL(accessToken);
DependencyManager::get<AccountManager>()->setAccessTokenForCurrentAuthURL(accessToken);
return true;
@ -461,7 +462,7 @@ void DomainServer::setupAutomaticNetworking() {
nodeList->startSTUNPublicSocketUpdate();
} else {
// send our heartbeat to data server so it knows what our network settings are
sendHeartbeatToDataServer();
sendHeartbeatToMetaverse();
}
} else {
qDebug() << "Cannot enable domain-server automatic networking without a domain ID."
@ -470,7 +471,7 @@ void DomainServer::setupAutomaticNetworking() {
return;
}
} else {
sendHeartbeatToDataServer();
sendHeartbeatToMetaverse();
}
qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting;
@ -479,7 +480,7 @@ void DomainServer::setupAutomaticNetworking() {
const int DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS = 15 * 1000;
QTimer* dataHeartbeatTimer = new QTimer(this);
connect(dataHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToDataServer()));
connect(dataHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse()));
dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS);
}
@ -499,17 +500,17 @@ void DomainServer::setupICEHeartbeatForFullNetworking() {
limitedNodeList->startSTUNPublicSocketUpdate();
// to send ICE heartbeats we'd better have a private key locally with an uploaded public key
auto& accountManager = AccountManager::getInstance();
auto domainID = accountManager.getAccountInfo().getDomainID();
auto accountManager = DependencyManager::get<AccountManager>();
auto domainID = accountManager->getAccountInfo().getDomainID();
// if we have an access token and we don't have a private key or the current domain ID has changed
// we should generate a new keypair
if (!accountManager.getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) {
accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID());
if (!accountManager->getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) {
accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
}
// hookup to the signal from account manager that tells us when keypair is available
connect(&accountManager, &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
connect(accountManager.data(), &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange);
if (!_iceHeartbeatTimer) {
// setup a timer to heartbeat with the ice-server every so often
@ -677,6 +678,9 @@ void DomainServer::processListRequestPacket(QSharedPointer<ReceivedMessage> mess
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(sendingNode->getLinkedData());
nodeData->setNodeInterestSet(nodeRequestData.interestList.toSet());
// update the connecting hostname in case it has changed
nodeData->setPlaceName(nodeRequestData.placeName);
sendDomainListToNode(sendingNode, message->getSenderSockAddr());
}
@ -962,9 +966,9 @@ void DomainServer::setupPendingAssignmentCredits() {
void DomainServer::sendPendingTransactionsToServer() {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager.hasValidAccessToken()) {
if (accountManager->hasValidAccessToken()) {
// enumerate the pending transactions and send them to the server to complete payment
TransactionHash::iterator i = _pendingAssignmentCredits.begin();
@ -975,7 +979,7 @@ void DomainServer::sendPendingTransactionsToServer() {
transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback";
while (i != _pendingAssignmentCredits.end()) {
accountManager.sendRequest("api/v1/transactions",
accountManager->sendRequest("api/v1/transactions",
AccountManagerAuth::Required,
QNetworkAccessManager::PostOperation,
transactionCallbackParams, i.value()->postJson().toJson());
@ -1028,11 +1032,11 @@ QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) {
const QString DOMAIN_UPDATE_AUTOMATIC_NETWORKING_KEY = "automatic_networking";
void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) {
sendHeartbeatToDataServer(newPublicSockAddr.getAddress().toString());
sendHeartbeatToMetaverse(newPublicSockAddr.getAddress().toString());
}
void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
auto nodeList = DependencyManager::get<LimitedNodeList>();
@ -1055,25 +1059,39 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
domainObject[RESTRICTED_ACCESS_FLAG] =
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
// add the number of currently connected agent users
int numConnectedAuthedUsers = 0;
// figure out the breakdown of currently connected interface clients
int numConnectedUnassigned = 0;
QJsonObject userHostnames;
nodeList->eachNode([&numConnectedAuthedUsers](const SharedNodePointer& node){
if (node->getLinkedData() && !static_cast<DomainServerNodeData*>(node->getLinkedData())->getUsername().isEmpty()) {
++numConnectedAuthedUsers;
static const QString DEFAULT_HOSTNAME = "*";
nodeList->eachNode([&numConnectedUnassigned, &userHostnames](const SharedNodePointer& node) {
if (node->getLinkedData()) {
auto nodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
if (!nodeData->wasAssigned()) {
++numConnectedUnassigned;
// increment the count for this hostname (or the default if we don't have one)
auto hostname = nodeData->getPlaceName().isEmpty() ? DEFAULT_HOSTNAME : nodeData->getPlaceName();
userHostnames[hostname] = userHostnames[hostname].toInt() + 1;
}
}
});
const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
const QString HEARTBEAT_NUM_USERS_KEY = "num_users";
static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
static const QString HEARTBEAT_NUM_USERS_KEY = "num_users";
static const QString HEARTBEAT_USER_HOSTNAMES_KEY = "user_hostnames";
QJsonObject heartbeatObject;
heartbeatObject[HEARTBEAT_NUM_USERS_KEY] = numConnectedAuthedUsers;
heartbeatObject[HEARTBEAT_NUM_USERS_KEY] = numConnectedUnassigned;
heartbeatObject[HEARTBEAT_USER_HOSTNAMES_KEY] = userHostnames;
domainObject[DOMAIN_HEARTBEAT_KEY] = heartbeatObject;
QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson()));
AccountManager::getInstance().sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
AccountManagerAuth::Required,
QNetworkAccessManager::PutOperation,
JSONCallbackParameters(),
@ -1103,7 +1121,7 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() {
static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address";
AccountManager::getInstance().sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
DependencyManager::get<AccountManager>()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)),
AccountManagerAuth::Optional,
QNetworkAccessManager::PutOperation,
callbackParameters,
@ -1123,15 +1141,15 @@ void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply& requestRepl
void DomainServer::sendHeartbeatToIceServer() {
if (!_iceServerSocket.getAddress().isNull()) {
auto& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
if (!accountManager.getAccountInfo().hasPrivateKey()) {
if (!accountManager->getAccountInfo().hasPrivateKey()) {
qWarning() << "Cannot send an ice-server heartbeat without a private key for signature.";
qWarning() << "Waiting for keypair generation to complete before sending ICE heartbeat.";
if (!limitedNodeList->getSessionUUID().isNull()) {
accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID());
accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
} else {
qWarning() << "Attempting to send ICE server heartbeat with no domain ID. This is not supported";
}
@ -1208,7 +1226,7 @@ void DomainServer::sendHeartbeatToIceServer() {
auto plaintext = QByteArray::fromRawData(_iceServerHeartbeatPacket->getPayload(), _iceServerHeartbeatPacket->getPayloadSize());
// generate a signature for the plaintext data in the packet
auto signature = accountManager.getAccountInfo().signPlaintext(plaintext);
auto signature = accountManager->getAccountInfo().signPlaintext(plaintext);
// pack the signature with the data
heartbeatDataStream << signature;
@ -2101,7 +2119,7 @@ void DomainServer::processICEServerHeartbeatDenialPacket(QSharedPointer<Received
// we've hit our threshold of heartbeat denials, trigger a keypair re-generation
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
AccountManager::getInstance().generateNewDomainKeypair(limitedNodeList->getSessionUUID());
DependencyManager::get<AccountManager>()->generateNewDomainKeypair(limitedNodeList->getSessionUUID());
// reset our number of heartbeat denials
_numHeartbeatDenials = 0;

View file

@ -71,7 +71,7 @@ private slots:
void sendPendingTransactionsToServer();
void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr);
void sendHeartbeatToDataServer() { sendHeartbeatToDataServer(QString()); }
void sendHeartbeatToMetaverse() { sendHeartbeatToMetaverse(QString()); }
void sendHeartbeatToIceServer();
void handleConnectedNode(SharedNodePointer newNode);
@ -103,7 +103,7 @@ private:
void setupAutomaticNetworking();
void setupICEHeartbeatForFullNetworking();
void sendHeartbeatToDataServer(const QString& networkAddress);
void sendHeartbeatToMetaverse(const QString& networkAddress);
void randomizeICEServerAddress(bool shouldTriggerHostLookup);

View file

@ -56,6 +56,12 @@ public:
void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue);
void removeOverrideForKey(const QString& key, const QString& value);
const QString& getPlaceName() { return _placeName; }
void setPlaceName(const QString& placeName) { _placeName = placeName; }
bool wasAssigned() const { return _wasAssigned; };
void setWasAssigned(bool wasAssigned) { _wasAssigned = wasAssigned; }
private:
QJsonObject overrideValuesIfNeeded(const QJsonObject& newStats);
@ -75,6 +81,10 @@ private:
bool _isAuthenticated = true;
NodeSet _nodeInterestSet;
QString _nodeVersion;
QString _placeName;
bool _wasAssigned { false };
};
#endif // hifi_DomainServerNodeData_h

View file

@ -23,7 +23,7 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
dataStream >> newHeader.nodeType
>> newHeader.publicSockAddr >> newHeader.localSockAddr
>> newHeader.interestList;
>> newHeader.interestList >> newHeader.placeName;
newHeader.senderSockAddr = senderSockAddr;

View file

@ -27,6 +27,7 @@ public:
HifiSockAddr localSockAddr;
HifiSockAddr senderSockAddr;
QList<NodeType_t> interestList;
QString placeName;
};

View file

@ -4,10 +4,6 @@ project(${TARGET_NAME})
# set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "LeapMotion")
if(WIN32)
list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient")
endif()
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE)
if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR)

View file

@ -2,11 +2,11 @@
"name": "Spacemouse to Standard",
"channels": [
{ "from": "Spacemouse.TranslateX", "to": "Standard.RX" },
{ "from": "Spacemouse.TranslateX", "to": "Standard.LX" },
{ "from": "Spacemouse.TranslateY", "to": "Standard.LY" },
{ "from": "Spacemouse.TranslateZ", "to": "Standard.RY" },
{ "from": "Spacemouse.RotateZ", "to": "Standard.LX" },
{ "from": "Spacemouse.RotateZ", "to": "Standard.RX" },
{ "from": "Spacemouse.LeftButton", "to": "Standard.LB" },
{ "from": "Spacemouse.RightButton", "to": "Standard.RB" }

View file

@ -1,165 +0,0 @@
import QtQuick 2.5
QtObject {
readonly property string aboutApp: "About Interface";
readonly property string addRemoveFriends: "Add/Remove Friends...";
readonly property string addressBar: "Show Address Bar";
readonly property string animations: "Animations...";
readonly property string animDebugDrawAnimPose: "Debug Draw Animation";
readonly property string animDebugDrawDefaultPose: "Debug Draw Default Pose";
readonly property string animDebugDrawPosition: "Debug Draw Position";
readonly property string antialiasing: "Antialiasing";
readonly property string assetMigration: "ATP Asset Migration";
readonly property string assetServer: "Asset Server";
readonly property string atmosphere: "Atmosphere";
readonly property string attachments: "Attachments...";
readonly property string audioNetworkStats: "Audio Network Stats";
readonly property string audioNoiseReduction: "Audio Noise Reduction";
readonly property string audioScope: "Show Scope";
readonly property string audioScopeFiftyFrames: "Fifty";
readonly property string audioScopeFiveFrames: "Five";
readonly property string audioScopeFrames: "Display Frames";
readonly property string audioScopePause: "Pause Scope";
readonly property string audioScopeTwentyFrames: "Twenty";
readonly property string audioStatsShowInjectedStreams: "Audio Stats Show Injected Streams";
readonly property string audioTools: "Show Level Meter";
readonly property string autoMuteAudio: "Auto Mute Microphone";
readonly property string avatarReceiveStats: "Show Receive Stats";
readonly property string back: "Back";
readonly property string bandwidthDetails: "Bandwidth Details";
readonly property string binaryEyelidControl: "Binary Eyelid Control";
readonly property string bookmarkLocation: "Bookmark Location";
readonly property string bookmarks: "Bookmarks";
readonly property string cachesSize: "RAM Caches Size";
readonly property string calibrateCamera: "Calibrate Camera";
readonly property string cameraEntityMode: "Entity Mode";
readonly property string centerPlayerInView: "Center Player In View";
readonly property string chat: "Chat...";
readonly property string collisions: "Collisions";
readonly property string connexion: "Activate 3D Connexion Devices";
readonly property string console_: "Console...";
readonly property string controlWithSpeech: "Control With Speech";
readonly property string copyAddress: "Copy Address to Clipboard";
readonly property string copyPath: "Copy Path to Clipboard";
readonly property string coupleEyelids: "Couple Eyelids";
readonly property string crashInterface: "Crash Interface";
readonly property string debugAmbientOcclusion: "Debug Ambient Occlusion";
readonly property string decreaseAvatarSize: "Decrease Avatar Size";
readonly property string deleteBookmark: "Delete Bookmark...";
readonly property string disableActivityLogger: "Disable Activity Logger";
readonly property string disableEyelidAdjustment: "Disable Eyelid Adjustment";
readonly property string disableLightEntities: "Disable Light Entities";
readonly property string disableNackPackets: "Disable Entity NACK Packets";
readonly property string diskCacheEditor: "Disk Cache Editor";
readonly property string displayCrashOptions: "Display Crash Options";
readonly property string displayHandTargets: "Show Hand Targets";
readonly property string displayModelBounds: "Display Model Bounds";
readonly property string displayModelTriangles: "Display Model Triangles";
readonly property string displayModelElementChildProxies: "Display Model Element Children";
readonly property string displayModelElementProxy: "Display Model Element Bounds";
readonly property string displayDebugTimingDetails: "Display Timing Details";
readonly property string dontDoPrecisionPicking: "Don't Do Precision Picking";
readonly property string dontRenderEntitiesAsScene: "Don't Render Entities as Scene";
readonly property string echoLocalAudio: "Echo Local Audio";
readonly property string echoServerAudio: "Echo Server Audio";
readonly property string enable3DTVMode: "Enable 3DTV Mode";
readonly property string enableCharacterController: "Enable avatar collisions";
readonly property string expandMyAvatarSimulateTiming: "Expand /myAvatar/simulation";
readonly property string expandMyAvatarTiming: "Expand /myAvatar";
readonly property string expandOtherAvatarTiming: "Expand /otherAvatar";
readonly property string expandPaintGLTiming: "Expand /paintGL";
readonly property string expandUpdateTiming: "Expand /update";
readonly property string faceshift: "Faceshift";
readonly property string firstPerson: "First Person";
readonly property string fivePointCalibration: "5 Point Calibration";
readonly property string fixGaze: "Fix Gaze (no saccade)";
readonly property string forward: "Forward";
readonly property string frameTimer: "Show Timer";
readonly property string fullscreenMirror: "Mirror";
readonly property string help: "Help...";
readonly property string increaseAvatarSize: "Increase Avatar Size";
readonly property string independentMode: "Independent Mode";
readonly property string inputMenu: "Avatar>Input Devices";
readonly property string keyboardMotorControl: "Enable Keyboard Motor Control";
readonly property string leapMotionOnHMD: "Leap Motion on HMD";
readonly property string loadScript: "Open and Run Script File...";
readonly property string loadScriptURL: "Open and Run Script from URL...";
readonly property string lodTools: "LOD Tools";
readonly property string login: "Login";
readonly property string log: "Log";
readonly property string logExtraTimings: "Log Extra Timing Details";
readonly property string lowVelocityFilter: "Low Velocity Filter";
readonly property string meshVisible: "Draw Mesh";
readonly property string miniMirror: "Mini Mirror";
readonly property string muteAudio: "Mute Microphone";
readonly property string muteEnvironment: "Mute Environment";
readonly property string muteFaceTracking: "Mute Face Tracking";
readonly property string namesAboveHeads: "Names Above Heads";
readonly property string noFaceTracking: "None";
readonly property string octreeStats: "Entity Statistics";
readonly property string onePointCalibration: "1 Point Calibration";
readonly property string onlyDisplayTopTen: "Only Display Top Ten";
readonly property string outputMenu: "Display";
readonly property string packageModel: "Package Model...";
readonly property string pair: "Pair";
readonly property string physicsShowOwned: "Highlight Simulation Ownership";
readonly property string physicsShowHulls: "Draw Collision Hulls";
readonly property string pipelineWarnings: "Log Render Pipeline Warnings";
readonly property string preferences: "General...";
readonly property string quit: "Quit";
readonly property string reloadAllScripts: "Reload All Scripts";
readonly property string reloadContent: "Reload Content (Clears all caches)";
readonly property string renderBoundingCollisionShapes: "Show Bounding Collision Shapes";
readonly property string renderFocusIndicator: "Show Eye Focus";
readonly property string renderLookAtTargets: "Show Look-at Targets";
readonly property string renderLookAtVectors: "Show Look-at Vectors";
readonly property string renderResolution: "Scale Resolution";
readonly property string renderResolutionOne: "1";
readonly property string renderResolutionTwoThird: "2/3";
readonly property string renderResolutionHalf: "1/2";
readonly property string renderResolutionThird: "1/3";
readonly property string renderResolutionQuarter: "1/4";
readonly property string renderAmbientLight: "Ambient Light";
readonly property string renderAmbientLightGlobal: "Global";
readonly property string renderAmbientLight0: "OLD_TOWN_SQUARE";
readonly property string renderAmbientLight1: "GRACE_CATHEDRAL";
readonly property string renderAmbientLight2: "EUCALYPTUS_GROVE";
readonly property string renderAmbientLight3: "ST_PETERS_BASILICA";
readonly property string renderAmbientLight4: "UFFIZI_GALLERY";
readonly property string renderAmbientLight5: "GALILEOS_TOMB";
readonly property string renderAmbientLight6: "VINE_STREET_KITCHEN";
readonly property string renderAmbientLight7: "BREEZEWAY";
readonly property string renderAmbientLight8: "CAMPUS_SUNSET";
readonly property string renderAmbientLight9: "FUNSTON_BEACH_SUNSET";
readonly property string resetAvatarSize: "Reset Avatar Size";
readonly property string resetSensors: "Reset Sensors";
readonly property string runningScripts: "Running Scripts...";
readonly property string runTimingTests: "Run Timing Tests";
readonly property string scriptEditor: "Script Editor...";
readonly property string scriptedMotorControl: "Enable Scripted Motor Control";
readonly property string showDSConnectTable: "Show Domain Connection Timing";
readonly property string showBordersEntityNodes: "Show Entity Nodes";
readonly property string showRealtimeEntityStats: "Show Realtime Entity Stats";
readonly property string showWhosLookingAtMe: "Show Who's Looking at Me";
readonly property string standingHMDSensorMode: "Standing HMD Sensor Mode";
readonly property string simulateEyeTracking: "Simulate";
readonly property string sMIEyeTracking: "SMI Eye Tracking";
readonly property string stars: "Stars";
readonly property string stats: "Stats";
readonly property string stopAllScripts: "Stop All Scripts";
readonly property string suppressShortTimings: "Suppress Timings Less than 10ms";
readonly property string thirdPerson: "Third Person";
readonly property string threePointCalibration: "3 Point Calibration";
readonly property string throttleFPSIfNotFocus: "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp
readonly property string toolWindow: "Tool Window";
readonly property string transmitterDrive: "Transmitter Drive";
readonly property string turnWithHead: "Turn using Head";
readonly property string useAudioForMouth: "Use Audio for Mouth";
readonly property string useCamera: "Use Camera";
readonly property string velocityFilter: "Velocity Filter";
readonly property string visibleToEveryone: "Everyone";
readonly property string visibleToFriends: "Friends";
readonly property string visibleToNoOne: "No one";
readonly property string worldAxes: "World Axes";
}

View file

@ -108,7 +108,6 @@
#include "audio/AudioScope.h"
#include "avatar/AvatarManager.h"
#include "CrashHandler.h"
#include "input-plugins/SpacemouseManager.h"
#include "devices/DdeFaceTracker.h"
#include "devices/EyeTracker.h"
#include "devices/Faceshift.h"
@ -199,6 +198,7 @@ static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check f
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
static const QString INPUT_DEVICE_MENU_PREFIX = "Device: ";
Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTREE_PPS);
const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensions {
@ -402,6 +402,7 @@ bool setupEssentials(int& argc, char** argv) {
Setting::init();
// Set dependencies
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<ScriptEngines>();
DependencyManager::set<Preferences>();
DependencyManager::set<recording::Deck>();
@ -656,15 +657,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
// connect to appropriate slots on AccountManager
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
auto dialogsManager = DependencyManager::get<DialogsManager>();
connect(&accountManager, &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog);
connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setIsAgent(true);
accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
accountManager->setIsAgent(true);
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
@ -761,6 +762,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// Tell our entity edit sender about our known jurisdictions
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
_entityEditSender.setMyAvatar(getMyAvatar());
// For now we're going to set the PPS for outbound packets to be super high, this is
// probably not the right long term solution. But for now, we're going to do this to
@ -996,7 +998,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
RenderableWebEntityItem* webEntity = dynamic_cast<RenderableWebEntityItem*>(entity.get());
if (webEntity) {
webEntity->setProxyWindow(_window->windowHandle());
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->pluginFocusOutEvent();
}
_keyboardFocusedItem = entityItemID;
@ -1049,6 +1051,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// Make sure we don't time out during slow operations at startup
updateHeartbeat();
OctreeEditPacketSender* packetSender = entityScriptingInterface->getPacketSender();
EntityEditPacketSender* entityPacketSender = static_cast<EntityEditPacketSender*>(packetSender);
entityPacketSender->setMyAvatar(getMyAvatar());
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
@ -1057,6 +1063,38 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
firstRun.set(false);
}
QString Application::getUserAgent() {
if (QThread::currentThread() != thread()) {
QString userAgent;
QMetaObject::invokeMethod(this, "getUserAgent", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, userAgent));
return userAgent;
}
QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; "
+ QSysInfo::productType() + " " + QSysInfo::productVersion() + ")";
auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); };
// For each plugin, add to userAgent
auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins();
for (auto& dp : displayPlugins) {
if (dp->isActive() && dp->isHmd()) {
userAgent += " " + formatPluginName(dp->getName());
}
}
auto inputPlugins= PluginManager::getInstance()->getInputPlugins();
for (auto& ip : inputPlugins) {
if (ip->isActive()) {
userAgent += " " + formatPluginName(ip->getName());
}
}
return userAgent;
}
void Application::checkChangeCursor() {
QMutexLocker locker(&_changeCursorLock);
@ -1088,7 +1126,7 @@ void Application::aboutToQuit() {
emit beforeAboutToQuit();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
QString name = inputPlugin->getName();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action->isChecked()) {
inputPlugin->deactivate();
@ -1407,8 +1445,7 @@ void Application::initializeUi() {
// This will set up the input plugins UI
_activeInputPlugins.clear();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
QString name = inputPlugin->getName();
if (name == KeyboardMouseDevice::NAME) {
if (KeyboardMouseDevice::NAME == inputPlugin->getName()) {
_keyboardMouseDevice = std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin);
}
}
@ -1477,17 +1514,17 @@ void Application::paintGL() {
renderArgs._context->syncCache();
}
if (Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror)) {
auto inputs = AvatarInputs::getInstance();
if (inputs->mirrorVisible()) {
PerformanceTimer perfTimer("Mirror");
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
renderArgs._blitFramebuffer = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
auto inputs = AvatarInputs::getInstance();
_mirrorViewRect.moveTo(inputs->x(), inputs->y());
renderRearViewMirror(&renderArgs, _mirrorViewRect);
renderRearViewMirror(&renderArgs, _mirrorViewRect, inputs->mirrorZoomed());
renderArgs._blitFramebuffer.reset();
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
@ -1789,25 +1826,37 @@ bool Application::event(QEvent* event) {
return false;
}
static bool justPresented = false;
// Presentation/painting logic
// TODO: Decouple presentation and painting loops
static bool isPainting = false;
if ((int)event->type() == (int)Present) {
if (justPresented) {
justPresented = false;
// If presentation is hogging the main thread, repost as low priority to avoid hanging the GUI.
if (isPainting) {
// If painting (triggered by presentation) is hogging the main thread,
// repost as low priority to avoid hanging the GUI.
// This has the effect of allowing presentation to exceed the paint budget by X times and
// only dropping every (1/X) frames, instead of every ceil(X) frames.
// only dropping every (1/X) frames, instead of every ceil(X) frames
// (e.g. at a 60FPS target, painting for 17us would fall to 58.82FPS instead of 30FPS).
removePostedEvents(this, Present);
postEvent(this, new QEvent(static_cast<QEvent::Type>(Present)), Qt::LowEventPriority);
isPainting = false;
return true;
}
idle();
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
isPainting = true;
return true;
} else if ((int)event->type() == (int)Paint) {
justPresented = true;
// NOTE: This must be updated as close to painting as possible,
// or AvatarInputs will mysteriously move to the bottom-right
AvatarInputs::getInstance()->update();
paintGL();
isPainting = false;
return true;
}
@ -1940,7 +1989,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
}
if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->keyPressEvent(event);
}
@ -2274,7 +2323,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
return;
}
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->keyReleaseEvent(event);
}
@ -2306,7 +2355,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
void Application::focusOutEvent(QFocusEvent* event) {
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) {
QString name = inputPlugin->getName();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action && action->isChecked()) {
inputPlugin->pluginFocusOutEvent();
@ -2393,7 +2442,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
return;
}
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->mouseMoveEvent(event);
}
@ -2430,7 +2479,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->mousePressEvent(event);
}
@ -2475,7 +2524,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
}
if (hasFocus()) {
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->mouseReleaseEvent(event);
}
@ -2502,7 +2551,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
return;
}
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->touchUpdateEvent(event);
}
}
@ -2520,7 +2569,7 @@ void Application::touchBeginEvent(QTouchEvent* event) {
return;
}
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->touchBeginEvent(event);
}
@ -2537,7 +2586,7 @@ void Application::touchEndEvent(QTouchEvent* event) {
return;
}
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->touchEndEvent(event);
}
@ -2553,7 +2602,7 @@ void Application::wheelEvent(QWheelEvent* event) const {
return;
}
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
if (Menu::getInstance()->isOptionChecked(INPUT_DEVICE_MENU_PREFIX + KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->wheelEvent(event);
}
}
@ -2622,9 +2671,6 @@ void Application::idle() {
// Sync up the _renderedFrameIndex
_renderedFrameIndex = displayPlugin->presentCount();
// Request a paint ASAP
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority + 1);
// Update the deadlock watchdog
updateHeartbeat();
@ -2637,9 +2683,6 @@ void Application::idle() {
firstIdle = false;
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
_overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays));
} else {
// FIXME: AvatarInputs are positioned incorrectly if instantiated before the first paint
AvatarInputs::getInstance()->update();
}
PROFILE_RANGE(__FUNCTION__);
@ -2654,8 +2697,6 @@ void Application::idle() {
_keyboardDeviceHasFocus = true;
}
// We're going to execute idle processing, so restart the last idle timer
_lastTimeUpdated.start();
@ -2693,7 +2734,7 @@ void Application::idle() {
getActiveDisplayPlugin()->idle();
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
foreach(auto inputPlugin, inputPlugins) {
QString name = inputPlugin->getName();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
QAction* action = Menu::getInstance()->getActionForOption(name);
if (action && action->isChecked()) {
inputPlugin->idle();
@ -3336,22 +3377,18 @@ void Application::update(float deltaTime) {
};
InputPluginPointer keyboardMousePlugin;
bool jointsCaptured = false;
for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
if (inputPlugin->getName() == KeyboardMouseDevice::NAME) {
keyboardMousePlugin = inputPlugin;
} else if (inputPlugin->isActive()) {
inputPlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured);
if (inputPlugin->isJointController()) {
jointsCaptured = true;
}
inputPlugin->pluginUpdate(deltaTime, calibrationData);
}
}
userInputMapper->update(deltaTime);
if (keyboardMousePlugin && keyboardMousePlugin->isActive()) {
keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured);
keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData);
}
_controllerScriptingInterface->updateInputControllers();
@ -3557,10 +3594,6 @@ void Application::update(float deltaTime) {
int Application::sendNackPackets() {
if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
return 0;
}
// iterates through all nodes in NodeList
auto nodeList = DependencyManager::get<NodeList>();
@ -3655,11 +3688,11 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,
rootDetails.y * TREE_SCALE,
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
@ -3719,11 +3752,11 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,
rootDetails.y * TREE_SCALE,
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
@ -4068,7 +4101,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
activeRenderingThread = nullptr;
}
void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& region) {
void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed) {
auto originalViewport = renderArgs->_viewport;
// Grab current viewport to reset it at the end
@ -4078,7 +4111,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
auto myAvatar = getMyAvatar();
// bool eyeRelativeCamera = false;
if (!AvatarInputs::getInstance()->mirrorZoomed()) {
if (!isZoomed) {
_mirrorCamera.setPosition(myAvatar->getChestPosition() +
myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * myAvatar->getScale());
@ -4135,7 +4168,7 @@ void Application::updateWindowTitle() const {
auto nodeList = DependencyManager::get<NodeList>();
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
QString currentPlaceName = DependencyManager::get<AddressManager>()->getHost();
if (currentPlaceName.isEmpty()) {
@ -4162,6 +4195,7 @@ void Application::clearDomainOctreeDetails() {
qCDebug(interfaceapp) << "Clearing domain octree details...";
resetPhysicsReadyInformation();
getMyAvatar()->setAvatarEntityDataChanged(true); // to recreate worn entities
// reset our node to stats and node to jurisdiction maps... since these must be changing...
_entityServerJurisdictions.withWriteLock([&] {
@ -4250,9 +4284,9 @@ void Application::nodeKilled(SharedNodePointer node) {
return;
}
unsigned char* rootCode = _entityServerJurisdictions[nodeUUID].getRootOctalCode();
auto rootCode = _entityServerJurisdictions[nodeUUID].getRootOctalCode();
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
@ -4371,27 +4405,33 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
serverType = "Entity";
}
bool found = false;
jurisdiction->withReadLock([&] {
if (jurisdiction->find(nodeUUID) != jurisdiction->end()) {
found = true;
return;
}
VoxelPositionSize rootDetails;
voxelDetailsForCode(octreeStats.getJurisdictionRoot(), rootDetails);
voxelDetailsForCode(octreeStats.getJurisdictionRoot().get(), rootDetails);
qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",
qPrintable(serverType),
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
});
// store jurisdiction details for later use
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
// but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the
// details from the OctreeSceneStats to construct the JurisdictionMap
JurisdictionMap jurisdictionMap;
jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes());
jurisdiction->withWriteLock([&] {
(*jurisdiction)[nodeUUID] = jurisdictionMap;
});
if (!found) {
// store jurisdiction details for later use
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
// but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the
// details from the OctreeSceneStats to construct the JurisdictionMap
JurisdictionMap jurisdictionMap;
jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes());
jurisdiction->withWriteLock([&] {
(*jurisdiction)[nodeUUID] = jurisdictionMap;
});
}
});
return statsMessageLength;
@ -4775,8 +4815,8 @@ void Application::takeSnapshot() {
QString fileName = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot());
AccountManager& accountManager = AccountManager::getInstance();
if (!accountManager.isLoggedIn()) {
auto accountManager = DependencyManager::get<AccountManager>();
if (!accountManager->isLoggedIn()) {
return;
}
@ -5107,21 +5147,23 @@ void Application::updateDisplayMode() {
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
}
static void addInputPluginToMenu(InputPluginPointer inputPlugin, bool active = false) {
static void addInputPluginToMenu(InputPluginPointer inputPlugin) {
auto menu = Menu::getInstance();
QString name = inputPlugin->getName();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
Q_ASSERT(!menu->menuItemExists(MenuOption::InputMenu, name));
static QActionGroup* inputPluginGroup = nullptr;
if (!inputPluginGroup) {
inputPluginGroup = new QActionGroup(menu);
inputPluginGroup->setExclusive(false);
}
auto parent = menu->getMenu(MenuOption::InputMenu);
auto action = menu->addCheckableActionToQMenuAndActionHash(parent,
name, 0, active, qApp,
name, 0, true, qApp,
SLOT(updateInputModes()));
inputPluginGroup->addAction(action);
inputPluginGroup->setExclusive(false);
Q_ASSERT(menu->menuItemExists(MenuOption::InputMenu, name));
}
@ -5131,10 +5173,8 @@ void Application::updateInputModes() {
auto inputPlugins = PluginManager::getInstance()->getInputPlugins();
static std::once_flag once;
std::call_once(once, [&] {
bool first = true;
foreach(auto inputPlugin, inputPlugins) {
addInputPluginToMenu(inputPlugin, first);
first = false;
addInputPluginToMenu(inputPlugin);
}
});
auto offscreenUi = DependencyManager::get<OffscreenUi>();
@ -5142,7 +5182,7 @@ void Application::updateInputModes() {
InputPluginList newInputPlugins;
InputPluginList removedInputPlugins;
foreach(auto inputPlugin, inputPlugins) {
QString name = inputPlugin->getName();
QString name = INPUT_DEVICE_MENU_PREFIX + inputPlugin->getName();
QAction* action = menu->getActionForOption(name);
auto it = std::find(std::begin(_activeInputPlugins), std::end(_activeInputPlugins), inputPlugin);

View file

@ -112,6 +112,9 @@ public:
QString getPreviousScriptLocation();
void setPreviousScriptLocation(const QString& previousScriptLocation);
// Return an HTTP User-Agent string with OS and device information.
Q_INVOKABLE QString getUserAgent();
void initializeGL();
void initializeUi();
void paintGL();
@ -339,7 +342,7 @@ private:
glm::vec3 getSunDirection() const;
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region);
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed);
int sendNackPackets();

View file

@ -35,9 +35,9 @@ const QString API_USER_HEARTBEAT_PATH = "/api/v1/user/heartbeat";
const QString SESSION_ID_KEY = "session_id";
void DiscoverabilityManager::updateLocation() {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (_mode.get() != Discoverability::None && accountManager.isLoggedIn()) {
if (_mode.get() != Discoverability::None && accountManager->isLoggedIn()) {
auto addressManager = DependencyManager::get<AddressManager>();
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
@ -98,7 +98,7 @@ void DiscoverabilityManager::updateLocation() {
apiPath = API_USER_LOCATION_PATH;
}
accountManager.sendRequest(apiPath, AccountManagerAuth::Required,
accountManager->sendRequest(apiPath, AccountManagerAuth::Required,
QNetworkAccessManager::PutOperation,
callbackParameters, QJsonDocument(rootObject).toJson());
@ -116,7 +116,7 @@ void DiscoverabilityManager::updateLocation() {
heartbeatObject[SESSION_ID_KEY] = QJsonValue();
}
accountManager.sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
accountManager->sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
QNetworkAccessManager::PutOperation, callbackParameters,
QJsonDocument(heartbeatObject).toJson());
}
@ -131,8 +131,8 @@ void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply
}
void DiscoverabilityManager::removeLocation() {
AccountManager& accountManager = AccountManager::getInstance();
accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, QNetworkAccessManager::DeleteOperation);
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, QNetworkAccessManager::DeleteOperation);
}
void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) {

View file

@ -34,7 +34,6 @@
#include "avatar/AvatarManager.h"
#include "devices/DdeFaceTracker.h"
#include "devices/Faceshift.h"
#include "input-plugins/SpacemouseManager.h"
#include "MainWindow.h"
#include "render/DrawStatus.h"
#include "scripting/MenuScriptingInterface.h"
@ -54,7 +53,7 @@ Menu* Menu::getInstance() {
Menu::Menu() {
auto dialogsManager = DependencyManager::get<DialogsManager>();
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
// File/Application menu ----------------------------------
MenuWrapper* fileMenu = addMenu("File");
@ -64,9 +63,9 @@ Menu::Menu() {
addActionToQMenuAndActionHash(fileMenu, MenuOption::Login);
// connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item
connect(&accountManager, &AccountManager::profileChanged,
connect(accountManager.data(), &AccountManager::profileChanged,
dialogsManager.data(), &DialogsManager::toggleLoginDialog);
connect(&accountManager, &AccountManager::logoutComplete,
connect(accountManager.data(), &AccountManager::logoutComplete,
dialogsManager.data(), &DialogsManager::toggleLoginDialog);
}
@ -327,12 +326,6 @@ Menu::Menu() {
connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool)));
#endif
// Settings > Input Devices
MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced");
QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu);
inputModeGroup->setExclusive(false);
// Developer menu ----------------------------------
MenuWrapper* developerMenu = addMenu("Developer", "Developer");
@ -410,6 +403,12 @@ Menu::Menu() {
// Developer > Avatar >>>
MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar");
// Settings > Input Devices
MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced");
QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu);
inputModeGroup->setExclusive(false);
// Developer > Avatar > Face Tracking
MenuWrapper* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
{
@ -531,9 +530,6 @@ Menu::Menu() {
// Developer > Network >>>
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false,
qApp->getEntityEditPacketSender(),
SLOT(toggleNackPackets()));
addCheckableActionToQMenuAndActionHash(networkMenu,
MenuOption::DisableActivityLogger,
0,

View file

@ -84,7 +84,6 @@ namespace MenuOption {
const QString DisableActivityLogger = "Disable Activity Logger";
const QString DisableEyelidAdjustment = "Disable Eyelid Adjustment";
const QString DisableLightEntities = "Disable Light Entities";
const QString DisableNackPackets = "Disable Entity NACK Packets";
const QString DiskCacheEditor = "Disk Cache Editor";
const QString DisplayCrashOptions = "Display Crash Options";
const QString DisplayHandTargets = "Show Hand Targets";
@ -114,7 +113,7 @@ namespace MenuOption {
const QString Help = "Help...";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString InputMenu = "Avatar>Input Devices";
const QString InputMenu = "Developer>Avatar>Input Devices";
const QString ActionMotorControl = "Enable Default Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";

View file

@ -31,6 +31,7 @@
#include <SharedUtil.h>
#include <TextRenderer3D.h>
#include <TextureCache.h>
#include <VariantMapToScriptValue.h>
#include <DebugDraw.h>
#include "Application.h"
@ -102,6 +103,18 @@ Avatar::Avatar(RigPointer rig) :
Avatar::~Avatar() {
assert(isDead()); // mark dead before calling the dtor
EntityTreeRenderer* treeRenderer = qApp->getEntities();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
if (entityTree) {
entityTree->withWriteLock([&] {
AvatarEntityMap avatarEntities = getAvatarEntityData();
for (auto entityID : avatarEntities.keys()) {
entityTree->deleteEntity(entityID, true, true);
}
});
}
if (_motionState) {
delete _motionState;
_motionState = nullptr;
@ -157,6 +170,90 @@ void Avatar::animateScaleChanges(float deltaTime) {
}
}
void Avatar::updateAvatarEntities() {
// - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity()
// - updateAvatarEntity saves the bytes and sets _avatarEntityDataLocallyEdited
// - MyAvatar::update notices _avatarEntityDataLocallyEdited and calls sendIdentityPacket
// - sendIdentityPacket sends the entity bytes to the server which relays them to other interfaces
// - AvatarHashMap::processAvatarIdentityPacket on other interfaces call avatar->setAvatarEntityData()
// - setAvatarEntityData saves the bytes and sets _avatarEntityDataChanged = true
// - (My)Avatar::simulate notices _avatarEntityDataChanged and here we are...
if (!_avatarEntityDataChanged) {
return;
}
if (getID() == QUuid()) {
return; // wait until MyAvatar gets an ID before doing this.
}
EntityTreeRenderer* treeRenderer = qApp->getEntities();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
if (!entityTree) {
return;
}
bool success = true;
QScriptEngine scriptEngine;
entityTree->withWriteLock([&] {
AvatarEntityMap avatarEntities = getAvatarEntityData();
for (auto entityID : avatarEntities.keys()) {
// see EntityEditPacketSender::queueEditEntityMessage for the other end of this. unpack properties
// and either add or update the entity.
QByteArray jsonByteArray = avatarEntities.value(entityID);
QJsonDocument jsonProperties = QJsonDocument::fromBinaryData(jsonByteArray);
if (!jsonProperties.isObject()) {
qCDebug(interfaceapp) << "got bad avatarEntity json" << QString(jsonByteArray.toHex());
continue;
}
QVariant variantProperties = jsonProperties.toVariant();
QVariantMap asMap = variantProperties.toMap();
QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine);
EntityItemProperties properties;
EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, properties);
properties.setClientOnly(true);
properties.setOwningAvatarID(getID());
// there's no entity-server to tell us we're the simulation owner, so always set the
// simulationOwner to the owningAvatarID and a high priority.
properties.setSimulationOwner(getID(), AVATAR_ENTITY_SIMULATION_PRIORITY);
if (properties.getParentID() == AVATAR_SELF_ID) {
properties.setParentID(getID());
}
EntityItemPointer entity = entityTree->findEntityByEntityItemID(EntityItemID(entityID));
if (entity) {
if (entityTree->updateEntity(entityID, properties)) {
entity->updateLastEditedFromRemote();
} else {
success = false;
}
} else {
entity = entityTree->addEntity(entityID, properties);
if (!entity) {
success = false;
}
}
}
AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs();
foreach (auto entityID, recentlyDettachedAvatarEntities) {
if (!_avatarEntityData.contains(entityID)) {
entityTree->deleteEntity(entityID, true, true);
}
}
});
if (success) {
setAvatarEntityDataChanged(false);
}
}
void Avatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("simulate");
@ -229,6 +326,7 @@ void Avatar::simulate(float deltaTime) {
simulateAttachments(deltaTime);
updatePalms();
updateAvatarEntities();
}
bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
@ -1088,7 +1186,7 @@ void Avatar::setParentID(const QUuid& parentID) {
if (success) {
setTransform(beforeChangeTransform, success);
if (!success) {
qDebug() << "Avatar::setParentID failed to reset avatar's location.";
qCDebug(interfaceapp) << "Avatar::setParentID failed to reset avatar's location.";
}
}
}
@ -1103,7 +1201,7 @@ void Avatar::setParentJointIndex(quint16 parentJointIndex) {
if (success) {
setTransform(beforeChangeTransform, success);
if (!success) {
qDebug() << "Avatar::setParentJointIndex failed to reset avatar's location.";
qCDebug(interfaceapp) << "Avatar::setParentJointIndex failed to reset avatar's location.";
}
}
}

View file

@ -64,6 +64,7 @@ public:
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
void init();
void updateAvatarEntities();
void simulate(float deltaTime);
virtual void simulateAttachments(float deltaTime);

View file

@ -309,6 +309,10 @@ void MyAvatar::update(float deltaTime) {
head->setAudioLoudness(audio->getLastInputLoudness());
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
if (_avatarEntityDataLocallyEdited) {
sendIdentityPacket();
}
simulate(deltaTime);
currentEnergy += energyChargeRate;
@ -424,7 +428,14 @@ void MyAvatar::simulate(float deltaTime) {
EntityTreeRenderer* entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
if (entityTree) {
bool flyingAllowed = true;
bool ghostingAllowed = true;
entityTree->withWriteLock([&] {
std::shared_ptr<ZoneEntityItem> zone = entityTreeRenderer->myAvatarZone();
if (zone) {
flyingAllowed = zone->getFlyingAllowed();
ghostingAllowed = zone->getGhostingAllowed();
}
auto now = usecTimestampNow();
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
MovingEntitiesOperator moveOperator(entityTree);
@ -441,7 +452,8 @@ void MyAvatar::simulate(float deltaTime) {
EntityItemProperties properties = entity->getProperties();
properties.setQueryAACubeDirty();
properties.setLastEdited(now);
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties);
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entity->getID(), properties);
entity->setLastBroadcast(usecTimestampNow());
}
}
@ -452,7 +464,13 @@ void MyAvatar::simulate(float deltaTime) {
entityTree->recurseTreeWithOperator(&moveOperator);
}
});
_characterController.setFlyingAllowed(flyingAllowed);
if (!_characterController.isEnabled() && !ghostingAllowed) {
_characterController.setEnabled(true);
}
}
updateAvatarEntities();
}
// thread-safe
@ -700,6 +718,16 @@ void MyAvatar::saveData() {
}
settings.endArray();
settings.beginWriteArray("avatarEntityData");
int avatarEntityIndex = 0;
for (auto entityID : _avatarEntityData.keys()) {
settings.setArrayIndex(avatarEntityIndex);
settings.setValue("id", entityID);
settings.setValue("properties", _avatarEntityData.value(entityID));
avatarEntityIndex++;
}
settings.endArray();
settings.setValue("displayName", _displayName);
settings.setValue("collisionSoundURL", _collisionSoundURL);
settings.setValue("useSnapTurn", _useSnapTurn);
@ -811,6 +839,17 @@ void MyAvatar::loadData() {
settings.endArray();
setAttachmentData(attachmentData);
int avatarEntityCount = settings.beginReadArray("avatarEntityData");
for (int i = 0; i < avatarEntityCount; i++) {
settings.setArrayIndex(i);
QUuid entityID = settings.value("id").toUuid();
// QUuid entityID = QUuid::createUuid(); // generate a new ID
QByteArray properties = settings.value("properties").toByteArray();
updateAvatarEntity(entityID, properties);
}
settings.endArray();
setAvatarEntityDataChanged(true);
setDisplayName(settings.value("displayName").toString());
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
@ -1788,7 +1827,21 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
} else {
_motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
}
_characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
bool ghostingAllowed = true;
EntityTreeRenderer* entityTreeRenderer = qApp->getEntities();
if (entityTreeRenderer) {
std::shared_ptr<ZoneEntityItem> zone = entityTreeRenderer->myAvatarZone();
if (zone) {
ghostingAllowed = zone->getGhostingAllowed();
}
}
bool checked = menu->isOptionChecked(MenuOption::EnableCharacterController);
if (!ghostingAllowed) {
checked = true;
}
_characterController.setEnabled(checked);
}
void MyAvatar::clearDriveKeys() {

View file

@ -144,11 +144,11 @@ int main(int argc, const char* argv[]) {
// If we failed the OpenGLVersion check, log it.
if (override) {
auto& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {
UserActivityLogger::getInstance().insufficientGLVersion(glData);
} else {
QObject::connect(&AccountManager::getInstance(), &AccountManager::loginComplete, [glData](){
QObject::connect(accountManager.data(), &AccountManager::loginComplete, [glData](){
static bool loggedInsufficientGL = false;
if (!loggedInsufficientGL) {
UserActivityLogger::getInstance().insufficientGLVersion(glData);
@ -168,9 +168,9 @@ int main(int argc, const char* argv[]) {
QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection, Qt::DirectConnection);
#ifdef HAS_BUGSPLAT
AccountManager& accountManager = AccountManager::getInstance();
crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager.getAccountInfo().getUsername()));
QObject::connect(&accountManager, &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
auto accountManager = DependencyManager::get<AccountManager>();
crashReporter.mpSender.setDefaultUserName(qPrintable(accountManager->getAccountInfo().getUsername()));
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, &app, [&crashReporter](const QString& newUsername) {
crashReporter.mpSender.setDefaultUserName(qPrintable(newUsername));
});

View file

@ -19,14 +19,14 @@ AccountScriptingInterface* AccountScriptingInterface::getInstance() {
}
bool AccountScriptingInterface::isLoggedIn() {
AccountManager& accountManager = AccountManager::getInstance();
return accountManager.isLoggedIn();
auto accountManager = DependencyManager::get<AccountManager>();
return accountManager->isLoggedIn();
}
QString AccountScriptingInterface::getUsername() {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
return accountManager.getAccountInfo().getUsername();
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) {
return accountManager->getAccountInfo().getUsername();
} else {
return "Unknown user";
}

View file

@ -17,10 +17,10 @@
#include "GlobalServicesScriptingInterface.h"
GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
AccountManager& accountManager = AccountManager::getInstance();
connect(&accountManager, &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
connect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
connect(&accountManager, &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
auto accountManager = DependencyManager::get<AccountManager>();
connect(accountManager.data(), &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
connect(accountManager.data(), &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
connect(accountManager.data(), &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
_downloading = false;
QTimer* checkDownloadTimer = new QTimer(this);
@ -34,10 +34,10 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() {
}
GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() {
AccountManager& accountManager = AccountManager::getInstance();
disconnect(&accountManager, &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
disconnect(&accountManager, &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
disconnect(&accountManager, &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
auto accountManager = DependencyManager::get<AccountManager>();
disconnect(accountManager.data(), &AccountManager::usernameChanged, this, &GlobalServicesScriptingInterface::myUsernameChanged);
disconnect(accountManager.data(), &AccountManager::logoutComplete, this, &GlobalServicesScriptingInterface::loggedOut);
disconnect(accountManager.data(), &AccountManager::loginComplete, this, &GlobalServicesScriptingInterface::connected);
}
GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance() {
@ -46,7 +46,7 @@ GlobalServicesScriptingInterface* GlobalServicesScriptingInterface::getInstance(
}
const QString& GlobalServicesScriptingInterface::getUsername() const {
return AccountManager::getInstance().getAccountInfo().getUsername();
return DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
}
void GlobalServicesScriptingInterface::loggedOut() {

View file

@ -24,14 +24,15 @@ HIFI_QML_DEF(LoginDialog)
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent),
_rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString())
{
connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
auto accountManager = DependencyManager::get<AccountManager>();
connect(accountManager.data(), &AccountManager::loginComplete,
this, &LoginDialog::handleLoginCompleted);
connect(&AccountManager::getInstance(), &AccountManager::loginFailed,
connect(accountManager.data(), &AccountManager::loginFailed,
this, &LoginDialog::handleLoginFailed);
}
void LoginDialog::toggleAction() {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
Q_CHECK_PTR(loginAction);
static QMetaObject::Connection connection;
@ -39,10 +40,10 @@ void LoginDialog::toggleAction() {
disconnect(connection);
}
if (accountManager.isLoggedIn()) {
if (accountManager->isLoggedIn()) {
// change the menu item to logout
loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername());
connection = connect(loginAction, &QAction::triggered, &accountManager, &AccountManager::logout);
loginAction->setText("Logout " + accountManager->getAccountInfo().getUsername());
connection = connect(loginAction, &QAction::triggered, accountManager.data(), &AccountManager::logout);
} else {
// change the menu item to login
loginAction->setText("Login");
@ -78,7 +79,7 @@ QString LoginDialog::rootUrl() const {
void LoginDialog::login(const QString& username, const QString& password) {
qDebug() << "Attempting to login " << username;
setStatusText("Logging in...");
AccountManager::getInstance().requestAccessToken(username, password);
DependencyManager::get<AccountManager>()->requestAccessToken(username, password);
}
void LoginDialog::openUrl(const QString& url) {

View file

@ -433,13 +433,13 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
}
const JurisdictionMap& map = serverJurisdictions[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (rootCode) {
QString rootCodeHex = octalCodeToHexString(rootCode);
QString rootCodeHex = octalCodeToHexString(rootCode.get());
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverDetails << " jurisdiction: "
<< qPrintable(rootCodeHex)

View file

@ -92,7 +92,7 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) {
QUrl currentURL = DependencyManager::get<AddressManager>()->currentAddress();
shot.setText(URL, currentURL.toString());
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
// normalize username, replace all non alphanumeric with '-'
username.replace(QRegExp("[^A-Za-z0-9_]"), "-");
@ -144,14 +144,15 @@ const QString SUCCESS_LABEL_TEMPLATE = "Success!!! Go check out your image ...<b
QString SnapshotUploader::uploadSnapshot(const QUrl& fileUrl) {
if (AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().isEmpty()) {
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->getAccountInfo().getDiscourseApiKey().isEmpty()) {
OffscreenUi::warning(nullptr, "", "Your Discourse API key is missing, you cannot share snapshots. Please try to relog.");
return QString();
}
QHttpPart apiKeyPart;
apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"api_key\""));
apiKeyPart.setBody(AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().toLatin1());
apiKeyPart.setBody(accountManager->getAccountInfo().getDiscourseApiKey().toLatin1());
QString filename = fileUrl.toLocalFile();
qDebug() << filename;
@ -206,7 +207,7 @@ QString SnapshotUploader::sendForumPost(const QString& snapshotPath, const QStri
QUrl forumUrl(FORUM_POST_URL);
QUrlQuery query;
query.addQueryItem("api_key", AccountManager::getInstance().getAccountInfo().getDiscourseApiKey());
query.addQueryItem("api_key", DependencyManager::get<AccountManager>()->getAccountInfo().getDiscourseApiKey());
query.addQueryItem("topic_id", FORUM_REPLY_TO_TOPIC);
query.addQueryItem("raw", FORUM_POST_TEMPLATE.arg(snapshotPath, notes));
forumUrl.setQuery(query);

View file

@ -955,14 +955,16 @@ void AvatarData::clearJointsData() {
}
bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray& data) {
// this is used by the avatar-mixer
QDataStream packetStream(data);
QUuid avatarUUID;
QUrl unusedModelURL; // legacy faceModel support
QUrl skeletonModelURL;
QVector<AttachmentData> attachmentData;
AvatarEntityMap avatarEntityData;
QString displayName;
packetStream >> avatarUUID >> unusedModelURL >> skeletonModelURL >> attachmentData >> displayName;
packetStream >> avatarUUID >> unusedModelURL >> skeletonModelURL >> attachmentData >> displayName >> avatarEntityData;
bool hasIdentityChanged = false;
@ -982,6 +984,11 @@ bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray& data) {
hasIdentityChanged = true;
}
if (avatarEntityData != _avatarEntityData) {
setAvatarEntityData(avatarEntityData);
hasIdentityChanged = true;
}
return hasIdentityChanged;
}
@ -993,7 +1000,7 @@ QByteArray AvatarData::identityByteArray() {
QUrl unusedModelURL; // legacy faceModel support
identityStream << QUuid() << unusedModelURL << urlToSend << _attachmentData << _displayName;
identityStream << QUuid() << unusedModelURL << urlToSend << _attachmentData << _displayName << _avatarEntityData;
return identityData;
}
@ -1167,6 +1174,8 @@ void AvatarData::sendIdentityPacket() {
[&](const SharedNodePointer& node) {
nodeList->sendPacketList(std::move(packetList), *node);
});
_avatarEntityDataLocallyEdited = false;
}
void AvatarData::updateJointMappings() {
@ -1339,6 +1348,7 @@ static const QString JSON_AVATAR_HEAD_MODEL = QStringLiteral("headModel");
static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel");
static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
QJsonValue toJsonValue(const JointData& joint) {
@ -1377,6 +1387,17 @@ QJsonObject AvatarData::toJson() const {
root[JSON_AVATAR_ATTACHEMENTS] = attachmentsJson;
}
if (!_avatarEntityData.empty()) {
QJsonArray avatarEntityJson;
for (auto entityID : _avatarEntityData.keys()) {
QVariantMap entityData;
entityData.insert("id", entityID);
entityData.insert("properties", _avatarEntityData.value(entityID));
avatarEntityJson.push_back(QVariant(entityData).toJsonObject());
}
root[JSON_AVATAR_ENTITIES] = avatarEntityJson;
}
auto recordingBasis = getRecordingBasis();
bool success;
Transform avatarTransform = getTransform(success);
@ -1476,6 +1497,13 @@ void AvatarData::fromJson(const QJsonObject& json) {
setAttachmentData(attachments);
}
// if (json.contains(JSON_AVATAR_ENTITIES) && json[JSON_AVATAR_ENTITIES].isArray()) {
// QJsonArray attachmentsJson = json[JSON_AVATAR_ATTACHEMENTS].toArray();
// for (auto attachmentJson : attachmentsJson) {
// // TODO -- something
// }
// }
// Joint rotations are relative to the avatar, so they require no basis correction
if (json.contains(JSON_AVATAR_JOINT_ARRAY)) {
QVector<JointData> jointArray;
@ -1628,9 +1656,69 @@ void AvatarData::setAttachmentsVariant(const QVariantList& variant) {
QVector<AttachmentData> newAttachments;
newAttachments.reserve(variant.size());
for (const auto& attachmentVar : variant) {
AttachmentData attachment;
AttachmentData attachment;
attachment.fromVariant(attachmentVar);
newAttachments.append(attachment);
}
setAttachmentData(newAttachments);
}
void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "updateAvatarEntity", Q_ARG(const QUuid&, entityID), Q_ARG(QByteArray, entityData));
return;
}
_avatarEntityData.insert(entityID, entityData);
_avatarEntityDataLocallyEdited = true;
}
void AvatarData::clearAvatarEntity(const QUuid& entityID) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "clearAvatarEntity", Q_ARG(const QUuid&, entityID));
return;
}
_avatarEntityData.remove(entityID);
_avatarEntityDataLocallyEdited = true;
}
AvatarEntityMap AvatarData::getAvatarEntityData() const {
if (QThread::currentThread() != thread()) {
AvatarEntityMap result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getAvatarEntityData", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(AvatarEntityMap, result));
return result;
}
return _avatarEntityData;
}
void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAvatarEntityData", Q_ARG(const AvatarEntityMap&, avatarEntityData));
return;
}
if (_avatarEntityData != avatarEntityData) {
// keep track of entities that were attached to this avatar but no longer are
AvatarEntityIDs previousAvatarEntityIDs = QSet<QUuid>::fromList(_avatarEntityData.keys());
_avatarEntityData = avatarEntityData;
setAvatarEntityDataChanged(true);
foreach (auto entityID, previousAvatarEntityIDs) {
if (!_avatarEntityData.contains(entityID)) {
_avatarEntityDetached.insert(entityID);
}
}
}
}
AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() {
if (QThread::currentThread() != thread()) {
AvatarEntityIDs result;
QMetaObject::invokeMethod(const_cast<AvatarData*>(this), "getRecentlyDetachedIDs", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(AvatarEntityIDs, result));
return result;
}
AvatarEntityIDs result = _avatarEntityDetached;
_avatarEntityDetached.clear();
return result;
}

View file

@ -61,6 +61,8 @@ typedef unsigned long long quint64;
using AvatarSharedPointer = std::shared_ptr<AvatarData>;
using AvatarWeakPointer = std::weak_ptr<AvatarData>;
using AvatarHash = QHash<QUuid, AvatarSharedPointer>;
using AvatarEntityMap = QMap<QUuid, QByteArray>;
using AvatarEntityIDs = QSet<QUuid>;
using AvatarDataSequenceNumber = uint16_t;
@ -134,6 +136,10 @@ class AttachmentData;
class Transform;
using TransformPointer = std::shared_ptr<Transform>;
// When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead. This allows
// the value to be reset when the sessionID changes.
const QUuid AVATAR_SELF_ID = QUuid("{00000000-0000-0000-0000-000000000001}");
class AvatarData : public QObject, public SpatiallyNestable {
Q_OBJECT
@ -272,6 +278,9 @@ public:
Q_INVOKABLE QVariantList getAttachmentsVariant() const;
Q_INVOKABLE void setAttachmentsVariant(const QVariantList& variant);
Q_INVOKABLE void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData);
Q_INVOKABLE void clearAvatarEntity(const QUuid& entityID);
void setForceFaceTrackerConnected(bool connected) { _forceFaceTrackerConnected = connected; }
// key state
@ -323,6 +332,11 @@ public:
glm::vec3 getClientGlobalPosition() { return _globalPosition; }
Q_INVOKABLE AvatarEntityMap getAvatarEntityData() const;
Q_INVOKABLE void setAvatarEntityData(const AvatarEntityMap& avatarEntityData);
void setAvatarEntityDataChanged(bool value) { _avatarEntityDataChanged = value; }
AvatarEntityIDs getAndClearRecentlyDetachedIDs();
public slots:
void sendAvatarDataPacket();
void sendIdentityPacket();
@ -390,6 +404,11 @@ protected:
// updates about one avatar to another.
glm::vec3 _globalPosition;
AvatarEntityIDs _avatarEntityDetached; // recently detached from this avatar
AvatarEntityMap _avatarEntityData;
bool _avatarEntityDataLocallyEdited { false };
bool _avatarEntityDataChanged { false };
private:
friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar);
static QUrl _defaultFullAvatarModelUrl;

View file

@ -107,21 +107,23 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer<ReceivedMessage> mess
}
void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
// this is used by clients
// setup a data stream to parse the packet
QDataStream identityStream(message->getMessage());
QUuid sessionUUID;
while (!identityStream.atEnd()) {
QUrl faceMeshURL, skeletonURL;
QVector<AttachmentData> attachmentData;
AvatarEntityMap avatarEntityData;
QString displayName;
identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> attachmentData >> displayName;
identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> attachmentData >> displayName >> avatarEntityData;
// mesh URL for a UUID, find avatar in our list
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode);
if (avatar->getSkeletonModelURL().isEmpty() || (avatar->getSkeletonModelURL() != skeletonURL)) {
avatar->setSkeletonModelURL(skeletonURL); // Will expand "" to default and so will not continuously fire
}
@ -130,6 +132,8 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
avatar->setAttachmentData(attachmentData);
}
avatar->setAvatarEntityData(avatarEntityData);
if (avatar->getDisplayName() != displayName) {
avatar->setDisplayName(displayName);
}

View file

@ -121,16 +121,8 @@ namespace controller {
return availableInputs;
}
void ActionsDevice::update(float deltaTime, const InputCalibrationData& inpuCalibrationData, bool jointsCaptured) {
}
void ActionsDevice::focusOutEvent() {
}
ActionsDevice::ActionsDevice() : InputDevice("Actions") {
_deviceID = UserInputMapper::ACTIONS_DEVICE;
}
ActionsDevice::~ActionsDevice() {}
}

View file

@ -109,13 +109,11 @@ class ActionsDevice : public QObject, public InputDevice {
Q_PROPERTY(QString name READ getName)
public:
virtual EndpointPointer createEndpoint(const Input& input) const override;
virtual Input::NamedVector getAvailableInputs() const override;
virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void focusOutEvent() override;
ActionsDevice();
virtual ~ActionsDevice();
EndpointPointer createEndpoint(const Input& input) const override;
Input::NamedVector getAvailableInputs() const override;
};
}

View file

@ -57,9 +57,9 @@ public:
// Update call MUST be called once per simulation loop
// It takes care of updating the action states and deltas
virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) = 0;
virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData) {};
virtual void focusOutEvent() = 0;
virtual void focusOutEvent() {};
int getDeviceID() { return _deviceID; }
void setDeviceID(int deviceID) { _deviceID = deviceID; }

View file

@ -22,12 +22,6 @@ StandardController::StandardController() : InputDevice("Standard") {
_deviceID = UserInputMapper::STANDARD_DEVICE;
}
StandardController::~StandardController() {
}
void StandardController::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
}
void StandardController::focusOutEvent() {
_axisStateMap.clear();
_buttonPressedMap.clear();

View file

@ -28,11 +28,9 @@ public:
virtual EndpointPointer createEndpoint(const Input& input) const override;
virtual Input::NamedVector getAvailableInputs() const override;
virtual QStringList getDefaultMappingConfigs() const override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void focusOutEvent() override;
StandardController();
virtual ~StandardController();
};
}

View file

@ -35,10 +35,7 @@ public:
const QString& getName() const { return _name; }
// Device functions
virtual Input::NamedVector getAvailableInputs() const override;
void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) override {}
void focusOutEvent() override {}
Input::NamedVector getAvailableInputs() const override;
void setInputVariant(const QString& name, ReadLambda lambda);

View file

@ -88,6 +88,8 @@ public:
// For Scene.shouldRenderEntities
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
signals:
void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event);
void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event);

View file

@ -47,6 +47,9 @@ namespace render {
}
void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters) {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
statusGetters.push_back([entity] () -> render::Item::Status::Value {
quint64 delta = usecTimestampNow() - entity->getLastEditedFromRemote();
const float WAIT_THRESHOLD_INV = 1.0f / (0.2f * USECS_PER_SECOND);
@ -81,9 +84,7 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status:
(unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET);
});
statusGetters.push_back([entity] () -> render::Item::Status::Value {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
statusGetters.push_back([entity, myNodeID] () -> render::Item::Status::Value {
bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID);
bool otherOwnSimulation = !weOwnSimulation && !entity->getSimulationOwner().isNull();
@ -106,4 +107,18 @@ void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status:
return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::HAS_ACTIONS);
});
statusGetters.push_back([entity, myNodeID] () -> render::Item::Status::Value {
if (entity->getClientOnly()) {
if (entity->getOwningAvatarID() == myNodeID) {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
} else {
return render::Item::Status::Value(1.0f, render::Item::Status::Value::RED,
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
}
}
return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN,
(unsigned char)RenderItemStatusIcon::CLIENT_ONLY);
});
}

View file

@ -26,6 +26,7 @@ enum class RenderItemStatusIcon {
SIMULATION_OWNER = 3,
HAS_ACTIONS = 4,
OTHER_SIMULATION_OWNER = 5,
CLIENT_ONLY = 6,
NONE = 255
};

View file

@ -48,13 +48,6 @@ RenderableModelEntityItem::~RenderableModelEntityItem() {
void RenderableModelEntityItem::setModelURL(const QString& url) {
auto& currentURL = getParsedModelURL();
if (_model && (currentURL != url)) {
// The machinery for updateModelBounds will give existing models the opportunity to fix their translation/rotation/scale/registration.
// The first two are straightforward, but the latter two have guards to make sure they don't happen after they've already been set.
// Here we reset those guards. This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
_model->setScaleToFit(false, getDimensions());
_model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
}
ModelEntityItem::setModelURL(url);
if (currentURL != getParsedModelURL() || !_model) {
@ -163,6 +156,14 @@ void RenderableModelEntityItem::remapTextures() {
}
void RenderableModelEntityItem::doInitialModelSimulation() {
// The machinery for updateModelBounds will give existing models the opportunity to fix their
// translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to
// make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the
// entity values to change -- it just allows the model to match once it comes in.
_model->setScaleToFit(false, getDimensions());
_model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
// now recalculate the bounds and registration
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());

View file

@ -981,7 +981,7 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
PhysicalEntitySimulationPointer peSimulation = std::static_pointer_cast<PhysicalEntitySimulation>(simulation);
EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr;
if (packetSender) {
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties);
packetSender->queueEditEntityMessage(PacketType::EntityEdit, tree, entity->getID(), properties);
}
});
});

View file

@ -10,6 +10,7 @@
//
#include <assert.h>
#include <QJsonDocument>
#include <PerfStat.h>
#include <OctalCode.h>
#include <udt/PacketHeaders.h>
@ -24,9 +25,7 @@ EntityEditPacketSender::EntityEditPacketSender() {
}
void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
if (_shouldProcessNack) {
processNackPacket(*message, sendingNode);
}
processNackPacket(*message, sendingNode);
}
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew) {
@ -35,18 +34,76 @@ void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByte
}
}
void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemID modelID,
const EntityItemProperties& properties) {
void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
EntityTreePointer entityTree,
EntityItemID entityItemID,
const EntityItemProperties& properties) {
if (!_shouldSend) {
return; // bail early
}
if (properties.getOwningAvatarID() != _myAvatar->getID()) {
return; // don't send updates for someone else's avatarEntity
}
assert(properties.getClientOnly());
// this is an avatar-based entity. update our avatar-data rather than sending to the entity-server
assert(_myAvatar);
if (!entityTree) {
qDebug() << "EntityEditPacketSender::queueEditEntityMessage null entityTree.";
return;
}
EntityItemPointer entity = entityTree->findEntityByEntityItemID(entityItemID);
if (!entity) {
qDebug() << "EntityEditPacketSender::queueEditEntityMessage can't find entity.";
return;
}
// the properties that get serialized into the avatar identity packet should be the entire set
// rather than just the ones being edited.
entity->setProperties(properties);
EntityItemProperties entityProperties = entity->getProperties();
QScriptValue scriptProperties = EntityItemNonDefaultPropertiesToScriptValue(&_scriptEngine, entityProperties);
QVariant variantProperties = scriptProperties.toVariant();
QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties);
// the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar
QJsonObject jsonObject = jsonProperties.object();
if (QUuid(jsonObject["parentID"].toString()) == _myAvatar->getID()) {
jsonObject["parentID"] = AVATAR_SELF_ID.toString();
}
jsonProperties = QJsonDocument(jsonObject);
QByteArray binaryProperties = jsonProperties.toBinaryData();
_myAvatar->updateAvatarEntity(entityItemID, binaryProperties);
entity->setLastBroadcast(usecTimestampNow());
return;
}
void EntityEditPacketSender::queueEditEntityMessage(PacketType type,
EntityTreePointer entityTree,
EntityItemID entityItemID,
const EntityItemProperties& properties) {
if (!_shouldSend) {
return; // bail early
}
if (properties.getClientOnly()) {
queueEditAvatarEntityMessage(type, entityTree, entityItemID, properties);
return;
}
QByteArray bufferOut(NLPacket::maxPayloadSize(type), 0);
if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, bufferOut)) {
if (EntityItemProperties::encodeEntityEditPacket(type, entityItemID, properties, bufferOut)) {
#ifdef WANT_DEBUG
qCDebug(entities) << "calling queueOctreeEditMessage()...";
qCDebug(entities) << " id:" << modelID;
qCDebug(entities) << " id:" << entityItemID;
qCDebug(entities) << " properties:" << properties;
#endif
queueOctreeEditMessage(type, bufferOut);
@ -58,6 +115,10 @@ void EntityEditPacketSender::queueEraseEntityMessage(const EntityItemID& entityI
return; // bail early
}
// in case this was a clientOnly entity:
assert(_myAvatar);
_myAvatar->clearAvatarEntity(entityItemID);
QByteArray bufferOut(NLPacket::maxPayloadSize(PacketType::EntityErase), 0);
if (EntityItemProperties::encodeEraseEntityMessage(entityItemID, bufferOut)) {

View file

@ -15,6 +15,7 @@
#include <OctreeEditPacketSender.h>
#include "EntityItem.h"
#include "AvatarData.h"
/// Utility for processing, packing, queueing and sending of outbound edit voxel messages.
class EntityEditPacketSender : public OctreeEditPacketSender {
@ -22,11 +23,21 @@ class EntityEditPacketSender : public OctreeEditPacketSender {
public:
EntityEditPacketSender();
void setMyAvatar(AvatarData* myAvatar) { _myAvatar = myAvatar; }
AvatarData* getMyAvatar() { return _myAvatar; }
void clearAvatarEntity(QUuid entityID) { assert(_myAvatar); _myAvatar->clearAvatarEntity(entityID); }
void queueEditAvatarEntityMessage(PacketType type, EntityTreePointer entityTree,
EntityItemID entityItemID, const EntityItemProperties& properties);
/// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines
/// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in
/// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known.
/// NOTE: EntityItemProperties assumes that all distances are in meter units
void queueEditEntityMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties);
void queueEditEntityMessage(PacketType type, EntityTreePointer entityTree,
EntityItemID entityItemID, const EntityItemProperties& properties);
void queueEraseEntityMessage(const EntityItemID& entityItemID);
@ -36,9 +47,9 @@ public:
public slots:
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
void toggleNackPackets() { _shouldProcessNack = !_shouldProcessNack; }
private:
bool _shouldProcessNack = true;
AvatarData* _myAvatar { nullptr };
QScriptEngine _scriptEngine;
};
#endif // hifi_EntityEditPacketSender_h

View file

@ -137,6 +137,9 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_PARENT_JOINT_INDEX;
requestedProperties += PROP_QUERY_AA_CUBE;
requestedProperties += PROP_CLIENT_ONLY;
requestedProperties += PROP_OWNING_AVATAR_ID;
return requestedProperties;
}
@ -1093,6 +1096,8 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
properties._id = getID();
properties._idSet = true;
properties._created = _created;
properties.setClientOnly(_clientOnly);
properties.setOwningAvatarID(_owningAvatarID);
properties._type = getType();
@ -1133,6 +1138,9 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localPosition, getLocalPosition);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRotation, getLocalOrientation);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(clientOnly, getClientOnly);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(owningAvatarID, getOwningAvatarID);
properties._defaultSettings = false;
return properties;
@ -1222,6 +1230,9 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(clientOnly, setClientOnly);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(owningAvatarID, setOwningAvatarID);
AACube saveQueryAACube = _queryAACube;
checkAndAdjustQueryAACube();
if (saveQueryAACube != _queryAACube) {

View file

@ -372,6 +372,7 @@ public:
glm::vec3 entityToWorld(const glm::vec3& point) const;
quint64 getLastEditedFromRemote() const { return _lastEditedFromRemote; }
void updateLastEditedFromRemote() { _lastEditedFromRemote = usecTimestampNow(); }
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
@ -422,12 +423,19 @@ public:
/// entity to definitively state if the preload signal should be sent.
///
/// We only want to preload if:
/// there is some script, and either the script value or the scriptTimestamp
/// there is some script, and either the script value or the scriptTimestamp
/// value have changed since our last preload
bool shouldPreloadScript() const { return !_script.isEmpty() &&
bool shouldPreloadScript() const { return !_script.isEmpty() &&
((_loadedScript != _script) || (_loadedScriptTimestamp != _scriptTimestamp)); }
void scriptHasPreloaded() { _loadedScript = _script; _loadedScriptTimestamp = _scriptTimestamp; }
bool getClientOnly() const { return _clientOnly; }
void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; }
// if this entity is client-only, which avatar is it associated with?
QUuid getOwningAvatarID() const { return _owningAvatarID; }
void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
protected:
void setSimulated(bool simulated) { _simulated = simulated; }
@ -539,6 +547,9 @@ protected:
mutable QHash<QUuid, quint64> _previouslyDeletedActions;
QUuid _sourceUUID; /// the server node UUID we came from
bool _clientOnly { false };
QUuid _owningAvatarID;
};
#endif // hifi_EntityItem_h

View file

@ -308,6 +308,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_LOCAL_POSITION, localPosition);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation);
CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed);
CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
CHECK_PROPERTY_CHANGE(PROP_CLIENT_ONLY, clientOnly);
CHECK_PROPERTY_CHANGE(PROP_OWNING_AVATAR_ID, owningAvatarID);
changedProperties += _animation.getChangedProperties();
changedProperties += _keyLight.getChangedProperties();
changedProperties += _skybox.getChangedProperties();
@ -465,6 +471,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
_stage.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
_skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
}
// Web only
@ -539,6 +548,12 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID);
properties.setProperty("clientOnly", convertScriptValue(engine, getClientOnly()));
properties.setProperty("owningAvatarID", convertScriptValue(engine, getOwningAvatarID()));
// FIXME - I don't think these properties are supported any more
//COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
@ -675,6 +690,12 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslationsSet, qVectorBool, setJointTranslationsSet);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslations, qVectorVec3, setJointTranslations);
COPY_PROPERTY_FROM_QSCRIPTVALUE(flyingAllowed, bool, setFlyingAllowed);
COPY_PROPERTY_FROM_QSCRIPTVALUE(ghostingAllowed, bool, setGhostingAllowed);
COPY_PROPERTY_FROM_QSCRIPTVALUE(clientOnly, bool, setClientOnly);
COPY_PROPERTY_FROM_QSCRIPTVALUE(owningAvatarID, QUuid, setOwningAvatarID);
_lastEdited = usecTimestampNow();
}
@ -845,6 +866,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_HOUR, Stage, stage, Hour, hour);
ADD_GROUP_PROPERTY_TO_MAP(PROP_STAGE_AUTOMATIC_HOURDAY, Stage, stage, AutomaticHourDay, automaticHourDay);
ADD_PROPERTY_TO_MAP(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool);
ADD_PROPERTY_TO_MAP(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool);
// FIXME - these are not yet handled
//ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64);
@ -1085,6 +1109,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
_staticSkybox.setProperties(properties);
_staticSkybox.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed());
}
if (properties.getType() == EntityTypes::PolyVox) {
@ -1369,6 +1396,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
}
if (properties.getType() == EntityTypes::PolyVox) {
@ -1559,6 +1589,12 @@ void EntityItemProperties::markAllChanged() {
_jointTranslationsChanged = true;
_queryAACubeChanged = true;
_flyingAllowedChanged = true;
_ghostingAllowedChanged = true;
_clientOnlyChanged = true;
_owningAvatarIDChanged = true;
}
// The minimum bounding box for the entity.
@ -1879,6 +1915,19 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (queryAACubeChanged()) {
out += "queryAACube";
}
if (clientOnlyChanged()) {
out += "clientOnly";
}
if (owningAvatarIDChanged()) {
out += "owningAvatarID";
}
if (flyingAllowedChanged()) {
out += "flyingAllowed";
}
if (ghostingAllowedChanged()) {
out += "ghostingAllowed";
}
getAnimation().listChangedProperties(out);
getKeyLight().listChangedProperties(out);

View file

@ -205,6 +205,12 @@ public:
DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector<bool>, QVector<bool>());
DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector<glm::vec3>, QVector<glm::vec3>());
DEFINE_PROPERTY(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool, ZoneEntityItem::DEFAULT_FLYING_ALLOWED);
DEFINE_PROPERTY(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool, ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED);
DEFINE_PROPERTY(PROP_CLIENT_ONLY, ClientOnly, clientOnly, bool, false);
DEFINE_PROPERTY_REF(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid, UNKNOWN_ENTITY_ID);
static QString getBackgroundModeString(BackgroundMode mode);
@ -416,6 +422,12 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, JointTranslationsSet, jointTranslationsSet, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, JointTranslations, jointTranslations, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, FlyingAllowed, flyingAllowed, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, GhostingAllowed, ghostingAllowed, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ClientOnly, clientOnly, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, OwningAvatarID, owningAvatarID, "");
properties.getAnimation().debugDump();
properties.getSkybox().debugDump();
properties.getStage().debugDump();

View file

@ -169,6 +169,12 @@ enum EntityPropertyList {
PROP_FALLOFF_RADIUS, // for Light entity
PROP_FLYING_ALLOWED, // can avatars in a zone fly?
PROP_GHOSTING_ALLOWED, // can avatars in a zone turn off physics?
PROP_CLIENT_ONLY, // doesn't go over wire
PROP_OWNING_AVATAR_ID, // doesn't go over wire
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -36,7 +36,7 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
EntityItemID entityID, const EntityItemProperties& properties) {
getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties);
getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);
}
bool EntityScriptingInterface::canAdjustLocks() {
@ -123,10 +123,17 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
}
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) {
EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties);
propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged());
if (clientOnly) {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID();
propertiesWithSimID.setClientOnly(clientOnly);
propertiesWithSimID.setOwningAvatarID(myNodeID);
}
auto dimensions = propertiesWithSimID.getDimensions();
float volume = dimensions.x * dimensions.y * dimensions.z;
auto density = propertiesWithSimID.getDensity();
@ -272,13 +279,21 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
bool updatedEntity = false;
_entityTree->withWriteLock([&] {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (!entity) {
return;
}
auto nodeList = DependencyManager::get<NodeList>();
if (entity->getClientOnly() && entity->getOwningAvatarID() != nodeList->getSessionUUID()) {
// don't edit other avatar's avatarEntities
return;
}
if (scriptSideProperties.parentRelatedPropertyChanged()) {
// All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them.
// If any of these changed, pull any missing properties from the entity.
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (!entity) {
return;
}
//existing entity, retrieve old velocity for check down below
oldVelocity = entity->getVelocity().length();
@ -296,6 +311,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
}
}
properties = convertLocationFromScriptSemantics(properties);
properties.setClientOnly(entity->getClientOnly());
properties.setOwningAvatarID(entity->getOwningAvatarID());
float cost = calculateCost(density * volume, oldVelocity, newVelocity);
cost *= costMultiplier;
@ -384,6 +401,14 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID();
if (entity->getClientOnly() && entity->getOwningAvatarID() != myNodeID) {
// don't delete other avatar's avatarEntities
shouldDelete = false;
return;
}
auto dimensions = entity->getDimensions();
float volume = dimensions.x * dimensions.y * dimensions.z;
auto density = entity->getDensity();
@ -771,6 +796,11 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
return false;
}
auto nodeList = DependencyManager::get<NodeList>();
const QUuid myNodeID = nodeList->getSessionUUID();
EntityItemProperties properties;
EntityItemPointer entity;
bool doTransmit = false;
_entityTree->withWriteLock([&] {
@ -786,15 +816,20 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
return;
}
if (entity->getClientOnly() && entity->getOwningAvatarID() != myNodeID) {
return;
}
doTransmit = actor(simulation, entity);
if (doTransmit) {
properties.setClientOnly(entity->getClientOnly());
properties.setOwningAvatarID(entity->getOwningAvatarID());
_entityTree->entityChanged(entity);
}
});
// transmit the change
if (doTransmit) {
EntityItemProperties properties;
_entityTree->withReadLock([&] {
properties = entity->getProperties();
});

View file

@ -82,7 +82,7 @@ public slots:
Q_INVOKABLE bool canRez();
/// adds a model with the specific properties
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties);
Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, bool clientOnly = false);
/// temporary method until addEntity can be used from QJSEngine
Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position);

View file

@ -311,7 +311,9 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result = NULL;
if (getIsClient()) {
bool clientOnly = properties.getClientOnly();
if (!clientOnly && getIsClient()) {
// if our Node isn't allowed to create entities in this domain, don't try.
auto nodeList = DependencyManager::get<NodeList>();
if (nodeList && !nodeList->getThisNodeCanRez()) {
@ -1376,10 +1378,17 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra
item->globalizeProperties(properties, "Cannot find %3 parent of %2 %1", args->root);
}
}
// set creation time to "now" for imported entities
properties.setCreated(usecTimestampNow());
properties.markAllChanged(); // so the entire property set is considered new, since we're making a new entity
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
EntityTreePointer tree = entityTreeElement->getTree();
// queue the packet to send to the server
args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, newID, properties);
args->packetSender->queueEditEntityMessage(PacketType::EntityAdd, tree, newID, properties);
// also update the local tree instantly (note: this is not our tree, but an alternate tree)
if (args->otherTree) {

View file

@ -27,6 +27,7 @@ const quint8 RECRUIT_SIMULATION_PRIORITY = VOLUNTEER_SIMULATION_PRIORITY + 1;
// When poking objects with scripts an observer will bid at SCRIPT_EDIT priority.
const quint8 SCRIPT_GRAB_SIMULATION_PRIORITY = 0x80;
const quint8 SCRIPT_POKE_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY - 1;
const quint8 AVATAR_ENTITY_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY + 1;
// PERSONAL priority (needs a better name) is the level at which a simulation observer owns its own avatar
// which really just means: things that collide with it will be bid at a priority level one lower

View file

@ -23,8 +23,12 @@
bool ZoneEntityItem::_zonesArePickable = false;
bool ZoneEntityItem::_drawZoneBoundaries = false;
const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX;
const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = "";
const bool ZoneEntityItem::DEFAULT_FLYING_ALLOWED = true;
const bool ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED = true;
EntityItemPointer ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity { new ZoneEntityItem(entityID) };
@ -55,6 +59,9 @@ EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredPr
_skyboxProperties.getProperties(properties);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed);
return properties;
}
@ -70,6 +77,9 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
bool somethingChangedInSkybox = _skyboxProperties.setProperties(properties);
somethingChanged = somethingChanged || somethingChangedInKeyLight || somethingChangedInStage || somethingChangedInSkybox;
@ -116,6 +126,9 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
bytesRead += bytesFromSkybox;
dataAt += bytesFromSkybox;
READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
return bytesRead;
}
@ -125,13 +138,16 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += _keyLightProperties.getEntityProperties(params);
requestedProperties += PROP_SHAPE_TYPE;
requestedProperties += PROP_COMPOUND_SHAPE_URL;
requestedProperties += PROP_BACKGROUND_MODE;
requestedProperties += _stageProperties.getEntityProperties(params);
requestedProperties += _skyboxProperties.getEntityProperties(params);
requestedProperties += PROP_FLYING_ALLOWED;
requestedProperties += PROP_GHOSTING_ALLOWED;
return requestedProperties;
}
@ -155,10 +171,12 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)getBackgroundMode()); // could this be a uint16??
_skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
}
void ZoneEntityItem::debugDump() const {

View file

@ -70,6 +70,11 @@ public:
const SkyboxPropertyGroup& getSkyboxProperties() const { return _skyboxProperties; }
const StagePropertyGroup& getStageProperties() const { return _stageProperties; }
bool getFlyingAllowed() const { return _flyingAllowed; }
void setFlyingAllowed(bool value) { _flyingAllowed = value; }
bool getGhostingAllowed() const { return _ghostingAllowed; }
void setGhostingAllowed(bool value) { _ghostingAllowed = value; }
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElementPointer& element, float& distance,
@ -80,18 +85,23 @@ public:
static const ShapeType DEFAULT_SHAPE_TYPE;
static const QString DEFAULT_COMPOUND_SHAPE_URL;
static const bool DEFAULT_FLYING_ALLOWED;
static const bool DEFAULT_GHOSTING_ALLOWED;
protected:
KeyLightPropertyGroup _keyLightProperties;
ShapeType _shapeType = DEFAULT_SHAPE_TYPE;
QString _compoundShapeURL;
BackgroundMode _backgroundMode = BACKGROUND_MODE_INHERIT;
StagePropertyGroup _stageProperties;
SkyboxPropertyGroup _skyboxProperties;
bool _flyingAllowed { DEFAULT_FLYING_ALLOWED };
bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
static bool _drawZoneBoundaries;
static bool _zonesArePickable;
};

View file

@ -25,7 +25,7 @@ public:
glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
if (original) {
if (original && original->_size) {
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
glBindBuffer(GL_COPY_READ_BUFFER, original->_buffer);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, original->_size);

View file

@ -20,11 +20,10 @@
const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
userInputMapper->withLock([&, this]() {
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
_inputDevice->update(deltaTime, inputCalibrationData);
});
// For touch event, we need to check that the last event is not too long ago
@ -40,7 +39,7 @@ void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputC
}
}
void KeyboardMouseDevice::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
void KeyboardMouseDevice::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
_axisStateMap.clear();
}

View file

@ -65,12 +65,11 @@ public:
};
// Plugin functions
virtual bool isSupported() const override { return true; }
virtual bool isJointController() const override { return false; }
virtual const QString& getName() const override { return NAME; }
bool isSupported() const override { return true; }
const QString& getName() const override { return NAME; }
virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event);
@ -97,7 +96,7 @@ protected:
// Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override;
virtual QString getDefaultMappingConfig() const override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
virtual void focusOutEvent() override;
// Let's make it easy for Qt because we assume we love Qt forever

View file

@ -36,16 +36,6 @@
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
AccountManager& AccountManager::getInstance(bool forceReset) {
static std::unique_ptr<AccountManager> sharedInstance(new AccountManager());
if (forceReset) {
sharedInstance.reset(new AccountManager());
}
return *sharedInstance;
}
Q_DECLARE_METATYPE(OAuthAccessToken)
Q_DECLARE_METATYPE(DataServerAccountInfo)
Q_DECLARE_METATYPE(QNetworkAccessManager::Operation)
@ -79,7 +69,8 @@ QJsonObject AccountManager::dataObjectFromResponse(QNetworkReply &requestReply)
}
}
AccountManager::AccountManager() :
AccountManager::AccountManager(UserAgentGetter userAgentGetter) :
_userAgentGetter(userAgentGetter),
_authURL(),
_pendingCallbackMap()
{
@ -222,8 +213,9 @@ void AccountManager::sendRequest(const QString& path,
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest;
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
QUrl requestURL = _authURL;
if (path.startsWith("/")) {
@ -473,7 +465,7 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest request;
request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
request.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
QUrl grantURL = _authURL;
grantURL.setPath("/oauth/token");
@ -543,7 +535,7 @@ void AccountManager::requestProfile() {
profileURL.setPath("/api/v1/user/profile");
QNetworkRequest profileRequest(profileURL);
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, _userAgentGetter());
profileRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, _accountInfo.getAccessToken().authorizationHeaderValue());
QNetworkReply* profileReply = networkAccessManager.get(profileRequest);

View file

@ -20,6 +20,9 @@
#include "NetworkAccessManager.h"
#include "DataServerAccountInfo.h"
#include "SharedUtil.h"
#include <DependencyManager.h>
class JSONCallbackParameters {
public:
@ -49,10 +52,14 @@ Q_DECLARE_METATYPE(AccountManagerAuth::Type);
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
class AccountManager : public QObject {
using UserAgentGetter = std::function<QString()>;
const auto DEFAULT_USER_AGENT_GETTER = []() -> QString { return HIGH_FIDELITY_USER_AGENT; };
class AccountManager : public QObject, public Dependency {
Q_OBJECT
public:
static AccountManager& getInstance(bool forceReset = false);
AccountManager(UserAgentGetter userAgentGetter = DEFAULT_USER_AGENT_GETTER);
Q_INVOKABLE void sendRequest(const QString& path,
AccountManagerAuth::Type authType,
@ -109,7 +116,6 @@ private slots:
void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid());
private:
AccountManager();
AccountManager(AccountManager const& other) = delete;
void operator=(AccountManager const& other) = delete;
@ -119,6 +125,8 @@ private:
void passSuccessToCallback(QNetworkReply* reply);
void passErrorToCallback(QNetworkReply* reply);
UserAgentGetter _userAgentGetter;
QUrl _authURL;
QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap;

View file

@ -295,14 +295,20 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
// set our current root place name to the name that came back
const QString PLACE_NAME_KEY = "name";
QString placeName = rootMap[PLACE_NAME_KEY].toString();
if (!placeName.isEmpty()) {
if (setHost(placeName, trigger)) {
trigger = LookupTrigger::Internal;
}
_placeName = placeName;
} else {
if (setHost(domainIDString, trigger)) {
trigger = LookupTrigger::Internal;
}
// this isn't a place, so clear the place name
_placeName.clear();
}
// check if we had a path to override the path returned
@ -374,7 +380,7 @@ void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const Q
// remember how this lookup was triggered for history storage handling later
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(trigger));
AccountManager::getInstance().sendRequest(GET_PLACE.arg(placeName),
DependencyManager::get<AccountManager>()->sendRequest(GET_PLACE.arg(placeName),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation,
apiCallbackParameters(),
@ -397,7 +403,7 @@ void AddressManager::attemptDomainIDLookup(const QString& lookupString, const QS
// remember how this lookup was triggered for history storage handling later
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(trigger));
AccountManager::getInstance().sendRequest(GET_DOMAIN_ID.arg(domainID),
DependencyManager::get<AccountManager>()->sendRequest(GET_DOMAIN_ID.arg(domainID),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation,
apiCallbackParameters(),
@ -577,11 +583,12 @@ bool AddressManager::setHost(const QString& host, LookupTrigger trigger, quint16
return false;
}
bool AddressManager::setDomainInfo(const QString& hostname, quint16 port, LookupTrigger trigger) {
bool hostChanged = setHost(hostname, trigger, port);
// clear any current place information
_rootPlaceID = QUuid();
_placeName.clear();
qCDebug(networking) << "Possible domain change required to connect to domain at" << hostname << "on" << port;
@ -600,7 +607,7 @@ void AddressManager::goToUser(const QString& username) {
requestParams.insert(LOOKUP_TRIGGER_KEY, static_cast<int>(LookupTrigger::UserInput));
// this is a username - pull the captured name and lookup that user's location
AccountManager::getInstance().sendRequest(GET_USER_LOCATION.arg(formattedUsername),
DependencyManager::get<AccountManager>()->sendRequest(GET_USER_LOCATION.arg(formattedUsername),
AccountManagerAuth::Optional,
QNetworkAccessManager::GetOperation,
apiCallbackParameters(),

View file

@ -58,6 +58,7 @@ public:
const QString currentPath(bool withOrientation = true) const;
const QUuid& getRootPlaceID() const { return _rootPlaceID; }
const QString& getPlaceName() const { return _placeName; }
const QString& getHost() const { return _host; }
@ -141,6 +142,7 @@ private:
QString _host;
quint16 _port;
QString _placeName;
QUuid _rootPlaceID;
PositionGetter _positionGetter;
OrientationGetter _orientationGetter;

View file

@ -371,10 +371,10 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
emit domainConnectionRefused(reason);
}
auto& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (!_hasCheckedForAccessToken) {
accountManager.checkAndSignalForAccessToken();
accountManager->checkAndSignalForAccessToken();
_hasCheckedForAccessToken = true;
}
@ -382,7 +382,7 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
// force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts
if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) {
accountManager.generateNewUserKeypair();
accountManager->generateNewUserKeypair();
_connectionDenialsSinceKeypairRegen = 0;
}
}

View file

@ -80,16 +80,16 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
// send a ping punch immediately
connect(&_domainHandler, &DomainHandler::icePeerSocketsReceived, this, &NodeList::pingPunchForDomainServer);
auto &accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
// assume that we may need to send a new DS check in anytime a new keypair is generated
connect(&accountManager, &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn);
connect(accountManager.data(), &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn);
// clear out NodeList when login is finished
connect(&accountManager, &AccountManager::loginComplete , this, &NodeList::reset);
connect(accountManager.data(), &AccountManager::loginComplete , this, &NodeList::reset);
// clear our NodeList when logout is requested
connect(&accountManager, &AccountManager::logoutComplete , this, &NodeList::reset);
connect(accountManager.data(), &AccountManager::logoutComplete , this, &NodeList::reset);
// anytime we get a new node we will want to attempt to punch to it
connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch);
@ -273,7 +273,7 @@ void NodeList::sendDomainServerCheckIn() {
}
// check if we're missing a keypair we need to verify ourselves with the domain-server
auto& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
const QUuid& connectionToken = _domainHandler.getConnectionToken();
// we assume that we're on the same box as the DS if it has the same local address and
@ -283,10 +283,10 @@ void NodeList::sendDomainServerCheckIn() {
bool requiresUsernameSignature = !_domainHandler.isConnected() && !connectionToken.isNull() && !localhostDomain;
if (requiresUsernameSignature && !accountManager.getAccountInfo().hasPrivateKey()) {
if (requiresUsernameSignature && !accountManager->getAccountInfo().hasPrivateKey()) {
qWarning() << "A keypair is required to present a username signature to the domain-server"
<< "but no keypair is present. Waiting for keypair generation to complete.";
accountManager.generateNewUserKeypair();
accountManager->generateNewUserKeypair();
// don't send the check in packet - wait for the keypair first
return;
@ -314,16 +314,18 @@ void NodeList::sendDomainServerCheckIn() {
packetStream << connectUUID;
}
// pack our data to send to the domain-server
packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList();
// pack our data to send to the domain-server including
// the hostname information (so the domain-server can see which place name we came in on)
packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList()
<< DependencyManager::get<AddressManager>()->getPlaceName();
if (!_domainHandler.isConnected()) {
DataServerAccountInfo& accountInfo = accountManager.getAccountInfo();
DataServerAccountInfo& accountInfo = accountManager->getAccountInfo();
packetStream << accountInfo.getUsername();
// if this is a connect request, and we can present a username signature, send it along
if (requiresUsernameSignature && accountManager.getAccountInfo().hasPrivateKey()) {
const QByteArray& usernameSignature = accountManager.getAccountInfo().getUsernameSignature(connectionToken);
if (requiresUsernameSignature && accountManager->getAccountInfo().hasPrivateKey()) {
const QByteArray& usernameSignature = accountManager->getAccountInfo().getUsernameSignature(connectionToken);
packetStream << usernameSignature;
}
}

View file

@ -32,14 +32,14 @@ OAuthNetworkAccessManager* OAuthNetworkAccessManager::getInstance() {
QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& req,
QIODevice* outgoingData) {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager.hasValidAccessToken()
if (accountManager->hasValidAccessToken()
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL.host()) {
QNetworkRequest authenticatedRequest(req);
authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
authenticatedRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER,
accountManager.getAccountInfo().getAccessToken().authorizationHeaderValue());
accountManager->getAccountInfo().getAccessToken().authorizationHeaderValue());
return QNetworkAccessManager::createRequest(op, authenticatedRequest, outgoingData);
} else {

View file

@ -17,6 +17,7 @@
#include "NetworkLogging.h"
#include "UserActivityLogger.h"
#include <DependencyManager.h>
static const QString USER_ACTIVITY_URL = "/api/v1/user_activities";
@ -34,7 +35,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
return;
}
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
// Adding the action name
@ -59,7 +60,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
params.errorCallbackMethod = "requestError";
}
accountManager.sendRequest(USER_ACTIVITY_URL,
accountManager->sendRequest(USER_ACTIVITY_URL,
AccountManagerAuth::Optional,
QNetworkAccessManager::PostOperation,
params, NULL, multipart);

View file

@ -47,10 +47,10 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityAdd:
case PacketType::EntityEdit:
case PacketType::EntityData:
return VERSION_LIGHT_HAS_FALLOFF_RADIUS;
return VERSION_ENTITIES_NO_FLY_ZONES;
case PacketType::AvatarData:
case PacketType::BulkAvatarData:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SoftAttachmentSupport);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarEntities);
case PacketType::ICEServerHeartbeat:
return 18; // ICE Server Heartbeat signing
case PacketType::AssetGetInfo:
@ -58,6 +58,9 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::AssetUpload:
// Removal of extension from Asset requests
return 18;
case PacketType::DomainConnectRequest:
// addition of referring hostname information
return 18;
default:
return 17;
}

View file

@ -171,10 +171,12 @@ const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54;
const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55;
const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56;
const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57;
const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58;
enum class AvatarMixerPacketVersion : PacketVersion {
TranslationSupport = 17,
SoftAttachmentSupport
SoftAttachmentSupport,
AvatarEntities
};
#endif // hifi_PacketHeaders_h

View file

@ -17,90 +17,11 @@
#include <DependencyManager.h>
#include <NodeList.h>
#include <udt/PacketHeaders.h>
#include <OctalCode.h>
#include "OctreeLogging.h"
#include "JurisdictionMap.h"
// standard assignment
// copy assignment
JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) {
copyContents(other);
return *this;
}
// Copy constructor
JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(NULL) {
copyContents(other);
}
void JurisdictionMap::copyContents(unsigned char* rootCodeIn, const std::vector<unsigned char*>& endNodesIn) {
unsigned char* rootCode;
std::vector<unsigned char*> endNodes;
if (rootCodeIn) {
size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(rootCodeIn));
rootCode = new unsigned char[bytes];
memcpy(rootCode, rootCodeIn, bytes);
} else {
rootCode = new unsigned char[1];
*rootCode = 0;
}
for (size_t i = 0; i < endNodesIn.size(); i++) {
if (endNodesIn[i]) {
size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodesIn[i]));
unsigned char* endNodeCode = new unsigned char[bytes];
memcpy(endNodeCode, endNodesIn[i], bytes);
endNodes.push_back(endNodeCode);
}
}
init(rootCode, endNodes);
}
void JurisdictionMap::copyContents(const JurisdictionMap& other) {
_nodeType = other._nodeType;
copyContents(other._rootOctalCode, other._endNodes);
}
JurisdictionMap::~JurisdictionMap() {
clear();
}
void JurisdictionMap::clear() {
if (_rootOctalCode) {
delete[] _rootOctalCode;
_rootOctalCode = NULL;
}
for (size_t i = 0; i < _endNodes.size(); i++) {
if (_endNodes[i]) {
delete[] _endNodes[i];
}
}
_endNodes.clear();
}
JurisdictionMap::JurisdictionMap(NodeType_t type) : _rootOctalCode(NULL) {
_nodeType = type;
unsigned char* rootCode = new unsigned char[1];
*rootCode = 0;
std::vector<unsigned char*> emptyEndNodes;
init(rootCode, emptyEndNodes);
}
JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(NULL) {
clear(); // clean up our own memory
readFromFile(filename);
}
JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes)
: _rootOctalCode(NULL) {
init(rootOctalCode, endNodes);
}
void myDebugoutputBits(unsigned char byte, bool withNewLine) {
void myDebugOutputBits(unsigned char byte, bool withNewLine) {
if (isalnum(byte)) {
printf("[ %d (%c): ", byte, byte);
} else {
@ -117,13 +38,12 @@ void myDebugoutputBits(unsigned char byte, bool withNewLine) {
}
}
void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) {
if (!octalCode) {
printf("NULL");
printf("nullptr");
} else {
for (size_t i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) {
myDebugoutputBits(octalCode[i],false);
myDebugOutputBits(octalCode[i], false);
}
}
if (withNewLine) {
@ -131,6 +51,55 @@ void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) {
}
}
// standard assignment
// copy assignment
JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) {
copyContents(other);
return *this;
}
// Copy constructor
JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(nullptr) {
copyContents(other);
}
void JurisdictionMap::copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn) {
OctalCodePtr rootCode = rootCodeIn;
if (!rootCode) {
rootCode = createOctalCodePtr(1);
*rootCode = 0;
}
OctalCodePtrList emptyEndNodes;
init(rootCode, endNodesIn);
}
void JurisdictionMap::copyContents(const JurisdictionMap& other) {
_nodeType = other._nodeType;
OctalCodePtr rootOctalCode;
OctalCodePtrList endNodes;
std::tie(rootOctalCode, endNodes) = other.getRootAndEndNodeOctalCodes();
init(rootOctalCode, endNodes);
}
JurisdictionMap::~JurisdictionMap() {
}
JurisdictionMap::JurisdictionMap(NodeType_t type) : _rootOctalCode(nullptr) {
_nodeType = type;
OctalCodePtr rootCode = createOctalCodePtr(1);
*rootCode = 0;
OctalCodePtrList emptyEndNodes;
init(rootCode, emptyEndNodes);
}
JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(nullptr) {
readFromFile(filename);
}
JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) {
@ -139,8 +108,8 @@ JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHe
_rootOctalCode = hexStringToOctalCode(QString(rootHexCode));
qCDebug(octree, "JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode);
myDebugPrintOctalCode(_rootOctalCode, true);
qCDebug(octree, "JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode.get());
myDebugPrintOctalCode(_rootOctalCode.get(), true);
QString endNodesHexStrings(endNodesHexCodes);
QString delimiterPattern(",");
@ -149,7 +118,7 @@ JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHe
for (int i = 0; i < endNodeList.size(); i++) {
QString endNodeHexString = endNodeList.at(i);
unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString);
auto endNodeOctcode = hexStringToOctalCode(endNodeHexString);
qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeList(%d)=%s",
i, endNodeHexString.toLocal8Bit().constData());
@ -157,15 +126,29 @@ JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHe
//printOctalCode(endNodeOctcode);
_endNodes.push_back(endNodeOctcode);
qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode);
myDebugPrintOctalCode(endNodeOctcode, true);
qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode.get());
myDebugPrintOctalCode(endNodeOctcode.get(), true);
}
}
std::tuple<OctalCodePtr, OctalCodePtrList> JurisdictionMap::getRootAndEndNodeOctalCodes() const {
std::lock_guard<std::mutex> lock(_octalCodeMutex);
return std::tuple<OctalCodePtr, OctalCodePtrList>(_rootOctalCode, _endNodes);
}
void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes) {
clear(); // clean up our own memory
OctalCodePtr JurisdictionMap::getRootOctalCode() const {
std::lock_guard<std::mutex> lock(_octalCodeMutex);
return _rootOctalCode;
}
OctalCodePtrList JurisdictionMap::getEndNodeOctalCodes() const {
std::lock_guard<std::mutex> lock(_octalCodeMutex);
return _endNodes;
}
void JurisdictionMap::init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes) {
std::lock_guard<std::mutex> lock(_octalCodeMutex);
_rootOctalCode = rootOctalCode;
_endNodes = endNodes;
}
@ -173,17 +156,19 @@ void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector<unsig
JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const {
// to be in our jurisdiction, we must be under the root...
std::lock_guard<std::mutex> lock(_octalCodeMutex);
// if the node is an ancestor of my root, then we return ABOVE
if (isAncestorOf(nodeOctalCode, _rootOctalCode)) {
if (isAncestorOf(nodeOctalCode, _rootOctalCode.get())) {
return ABOVE;
}
// otherwise...
bool isInJurisdiction = isAncestorOf(_rootOctalCode, nodeOctalCode, childIndex);
bool isInJurisdiction = isAncestorOf(_rootOctalCode.get(), nodeOctalCode, childIndex);
// if we're under the root, then we can't be under any of the endpoints
if (isInJurisdiction) {
for (size_t i = 0; i < _endNodes.size(); i++) {
bool isUnderEndNode = isAncestorOf(_endNodes[i], nodeOctalCode);
bool isUnderEndNode = isAncestorOf(_endNodes[i].get(), nodeOctalCode);
if (isUnderEndNode) {
isInJurisdiction = false;
break;
@ -200,8 +185,9 @@ bool JurisdictionMap::readFromFile(const char* filename) {
QString rootCode = settings.value("root","00").toString();
qCDebug(octree) << "rootCode=" << rootCode;
std::lock_guard<std::mutex> lock(_octalCodeMutex);
_rootOctalCode = hexStringToOctalCode(rootCode);
printOctalCode(_rootOctalCode);
printOctalCode(_rootOctalCode.get());
settings.beginGroup("endNodes");
const QStringList childKeys = settings.childKeys();
@ -211,8 +197,8 @@ bool JurisdictionMap::readFromFile(const char* filename) {
values.insert(childKey, childValue);
qCDebug(octree) << childKey << "=" << childValue;
unsigned char* octcode = hexStringToOctalCode(childValue);
printOctalCode(octcode);
auto octcode = hexStringToOctalCode(childValue);
printOctalCode(octcode.get());
_endNodes.push_back(octcode);
}
@ -221,12 +207,14 @@ bool JurisdictionMap::readFromFile(const char* filename) {
}
void JurisdictionMap::displayDebugDetails() const {
QString rootNodeValue = octalCodeToHexString(_rootOctalCode);
std::lock_guard<std::mutex> lock(_octalCodeMutex);
QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get());
qCDebug(octree) << "root:" << rootNodeValue;
for (size_t i = 0; i < _endNodes.size(); i++) {
QString value = octalCodeToHexString(_endNodes[i]);
QString value = octalCodeToHexString(_endNodes[i].get());
qCDebug(octree) << "End node[" << i << "]: " << rootNodeValue;
}
}
@ -236,15 +224,16 @@ bool JurisdictionMap::writeToFile(const char* filename) {
QString settingsFile(filename);
QSettings settings(settingsFile, QSettings::IniFormat);
std::lock_guard<std::mutex> lock(_octalCodeMutex);
QString rootNodeValue = octalCodeToHexString(_rootOctalCode);
QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get());
settings.setValue("root", rootNodeValue);
settings.beginGroup("endNodes");
for (size_t i = 0; i < _endNodes.size(); i++) {
QString key = QString("endnode%1").arg(i);
QString value = octalCodeToHexString(_endNodes[i]);
QString value = octalCodeToHexString(_endNodes[i].get());
settings.setValue(key, value);
}
settings.endGroup();
@ -271,18 +260,19 @@ std::unique_ptr<NLPacket> JurisdictionMap::packIntoPacket() {
packet->writePrimitive(type);
// add the root jurisdiction
std::lock_guard<std::mutex> lock(_octalCodeMutex);
if (_rootOctalCode) {
size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_rootOctalCode));
size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_rootOctalCode.get()));
// No root or end node details to pack!
packet->writePrimitive(bytes);
packet->write(reinterpret_cast<char*>(_rootOctalCode), bytes);
packet->write(reinterpret_cast<char*>(_rootOctalCode.get()), bytes);
// if and only if there's a root jurisdiction, also include the end nodes
int endNodeCount = (int)_endNodes.size();
packet->writePrimitive(endNodeCount);
for (int i=0; i < endNodeCount; i++) {
unsigned char* endNodeCode = _endNodes[i];
auto endNodeCode = _endNodes[i].get();
size_t bytes = 0;
if (endNodeCode) {
bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
@ -299,15 +289,17 @@ std::unique_ptr<NLPacket> JurisdictionMap::packIntoPacket() {
}
int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) {
clear();
// read the root jurisdiction
int bytes = 0;
message.readPrimitive(&bytes);
std::lock_guard<std::mutex> lock(_octalCodeMutex);
_rootOctalCode = nullptr;
_endNodes.clear();
if (bytes > 0 && bytes <= message.getBytesLeftToRead()) {
_rootOctalCode = new unsigned char[bytes];
message.read(reinterpret_cast<char*>(_rootOctalCode), bytes);
_rootOctalCode = createOctalCodePtr(bytes);
message.read(reinterpret_cast<char*>(_rootOctalCode.get()), bytes);
// if and only if there's a root jurisdiction, also include the end nodes
int endNodeCount = 0;
@ -318,8 +310,8 @@ int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) {
message.readPrimitive(&bytes);
if (bytes <= message.getBytesLeftToRead()) {
unsigned char* endNodeCode = new unsigned char[bytes];
message.read(reinterpret_cast<char*>(endNodeCode), bytes);
auto endNodeCode = createOctalCodePtr(bytes);
message.read(reinterpret_cast<char*>(endNodeCode.get()), bytes);
// if the endNodeCode was 0 length then don't add it
if (bytes > 0) {

View file

@ -23,6 +23,7 @@
#include <NLPacket.h>
#include <Node.h>
#include <OctalCode.h>
class JurisdictionMap {
public:
@ -41,8 +42,8 @@ public:
// application constructors
JurisdictionMap(const char* filename);
JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
~JurisdictionMap();
Area isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const;
@ -50,11 +51,12 @@ public:
bool writeToFile(const char* filename);
bool readFromFile(const char* filename);
unsigned char* getRootOctalCode() const { return _rootOctalCode; }
unsigned char* getEndNodeOctalCode(int index) const { return _endNodes[index]; }
int getEndNodeCount() const { return (int)_endNodes.size(); }
// Provide an atomic way to get both the rootOctalCode and endNodeOctalCodes.
std::tuple<OctalCodePtr, OctalCodePtrList> getRootAndEndNodeOctalCodes() const;
OctalCodePtr getRootOctalCode() const;
OctalCodePtrList getEndNodeOctalCodes() const;
void copyContents(unsigned char* rootCodeIn, const std::vector<unsigned char*>& endNodesIn);
void copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn);
int unpackFromPacket(ReceivedMessage& message);
std::unique_ptr<NLPacket> packIntoPacket();
@ -69,11 +71,11 @@ public:
private:
void copyContents(const JurisdictionMap& other); // use assignment instead
void clear();
void init(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
void init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes);
unsigned char* _rootOctalCode;
std::vector<unsigned char*> _endNodes;
mutable std::mutex _octalCodeMutex;
OctalCodePtr _rootOctalCode { nullptr };
OctalCodePtrList _endNodes;
NodeType_t _nodeType;
};

View file

@ -78,12 +78,12 @@ void OctreeHeadlessViewer::queryOctree() {
}
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (!rootCode) {
return;
}
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
foundRootDetails = true;
});
@ -146,7 +146,7 @@ void OctreeHeadlessViewer::queryOctree() {
}
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
auto rootCode = map.getRootOctalCode();
if (!rootCode) {
if (wantExtraDebugging) {
@ -154,7 +154,7 @@ void OctreeHeadlessViewer::queryOctree() {
}
return;
}
voxelDetailsForCode(rootCode, rootDetails);
voxelDetailsForCode(rootCode.get(), rootDetails);
foundRootDetails = true;
});

View file

@ -110,29 +110,21 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) {
_treesRemoved = other._treesRemoved;
// before copying the jurisdictions, delete any current values...
if (_jurisdictionRoot) {
delete[] _jurisdictionRoot;
_jurisdictionRoot = NULL;
}
for (size_t i = 0; i < _jurisdictionEndNodes.size(); i++) {
if (_jurisdictionEndNodes[i]) {
delete[] _jurisdictionEndNodes[i];
}
}
_jurisdictionRoot = nullptr;
_jurisdictionEndNodes.clear();
// Now copy the values from the other
if (other._jurisdictionRoot) {
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot));
_jurisdictionRoot = new unsigned char[bytes];
memcpy(_jurisdictionRoot, other._jurisdictionRoot, bytes);
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot.get()));
_jurisdictionRoot = createOctalCodePtr(bytes);
memcpy(_jurisdictionRoot.get(), other._jurisdictionRoot.get(), bytes);
}
for (size_t i = 0; i < other._jurisdictionEndNodes.size(); i++) {
unsigned char* endNodeCode = other._jurisdictionEndNodes[i];
auto& endNodeCode = other._jurisdictionEndNodes[i];
if (endNodeCode) {
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
unsigned char* endNodeCodeCopy = new unsigned char[bytes];
memcpy(endNodeCodeCopy, endNodeCode, bytes);
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get()));
auto endNodeCodeCopy = createOctalCodePtr(bytes);
memcpy(endNodeCodeCopy.get(), endNodeCode.get(), bytes);
_jurisdictionEndNodes.push_back(endNodeCodeCopy);
}
}
@ -162,37 +154,12 @@ void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, OctreeEleme
_isFullScene = isFullScene;
_isMoving = isMoving;
if (_jurisdictionRoot) {
delete[] _jurisdictionRoot;
_jurisdictionRoot = NULL;
}
// clear existing endNodes before copying new ones...
for (size_t i=0; i < _jurisdictionEndNodes.size(); i++) {
if (_jurisdictionEndNodes[i]) {
delete[] _jurisdictionEndNodes[i];
}
}
_jurisdictionEndNodes.clear();
// setup jurisdictions
if (jurisdictionMap) {
unsigned char* jurisdictionRoot = jurisdictionMap->getRootOctalCode();
if (jurisdictionRoot) {
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(jurisdictionRoot));
_jurisdictionRoot = new unsigned char[bytes];
memcpy(_jurisdictionRoot, jurisdictionRoot, bytes);
}
// copy new endNodes...
for (int i = 0; i < jurisdictionMap->getEndNodeCount(); i++) {
unsigned char* endNodeCode = jurisdictionMap->getEndNodeOctalCode(i);
if (endNodeCode) {
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
unsigned char* endNodeCodeCopy = new unsigned char[bytes];
memcpy(endNodeCodeCopy, endNodeCode, bytes);
_jurisdictionEndNodes.push_back(endNodeCodeCopy);
}
}
std::tie(_jurisdictionRoot, _jurisdictionEndNodes) = jurisdictionMap->getRootAndEndNodeOctalCodes();
} else {
_jurisdictionRoot = nullptr;
_jurisdictionEndNodes.clear();
}
}
@ -270,15 +237,7 @@ void OctreeSceneStats::reset() {
_existsInPacketBitsWritten = 0;
_treesRemoved = 0;
if (_jurisdictionRoot) {
delete[] _jurisdictionRoot;
_jurisdictionRoot = NULL;
}
for (size_t i = 0; i < _jurisdictionEndNodes.size(); i++) {
if (_jurisdictionEndNodes[i]) {
delete[] _jurisdictionEndNodes[i];
}
}
_jurisdictionRoot = nullptr;
_jurisdictionEndNodes.clear();
}
@ -418,9 +377,9 @@ int OctreeSceneStats::packIntoPacket() {
// add the root jurisdiction
if (_jurisdictionRoot) {
// copy the
int bytes = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot));
int bytes = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot.get()));
_statsPacket->writePrimitive(bytes);
_statsPacket->write(reinterpret_cast<char*>(_jurisdictionRoot), bytes);
_statsPacket->write(reinterpret_cast<char*>(_jurisdictionRoot.get()), bytes);
// if and only if there's a root jurisdiction, also include the end elements
int endNodeCount = (int)_jurisdictionEndNodes.size();
@ -428,10 +387,10 @@ int OctreeSceneStats::packIntoPacket() {
_statsPacket->writePrimitive(endNodeCount);
for (int i=0; i < endNodeCount; i++) {
unsigned char* endNodeCode = _jurisdictionEndNodes[i];
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode));
auto& endNodeCode = _jurisdictionEndNodes[i];
auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get()));
_statsPacket->writePrimitive(bytes);
_statsPacket->write(reinterpret_cast<char*>(endNodeCode), bytes);
_statsPacket->write(reinterpret_cast<char*>(endNodeCode.get()), bytes);
}
} else {
int bytes = 0;
@ -500,17 +459,7 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) {
packet.readPrimitive(&_existsInPacketBitsWritten);
packet.readPrimitive(&_treesRemoved);
// before allocating new juridiction, clean up existing ones
if (_jurisdictionRoot) {
delete[] _jurisdictionRoot;
_jurisdictionRoot = NULL;
}
// clear existing endNodes before copying new ones...
for (size_t i = 0; i < _jurisdictionEndNodes.size(); i++) {
if (_jurisdictionEndNodes[i]) {
delete[] _jurisdictionEndNodes[i];
}
}
_jurisdictionRoot = nullptr;
_jurisdictionEndNodes.clear();
// read the root jurisdiction
@ -518,11 +467,11 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) {
packet.readPrimitive(&bytes);
if (bytes == 0) {
_jurisdictionRoot = NULL;
_jurisdictionRoot = nullptr;
_jurisdictionEndNodes.clear();
} else {
_jurisdictionRoot = new unsigned char[bytes];
packet.read(reinterpret_cast<char*>(_jurisdictionRoot), bytes);
_jurisdictionRoot = createOctalCodePtr(bytes);
packet.read(reinterpret_cast<char*>(_jurisdictionRoot.get()), bytes);
// if and only if there's a root jurisdiction, also include the end elements
_jurisdictionEndNodes.clear();
@ -535,8 +484,8 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) {
packet.readPrimitive(&bytes);
unsigned char* endNodeCode = new unsigned char[bytes];
packet.read(reinterpret_cast<char*>(endNodeCode), bytes);
auto endNodeCode = createOctalCodePtr(bytes);
packet.read(reinterpret_cast<char*>(endNodeCode.get()), bytes);
_jurisdictionEndNodes.push_back(endNodeCode);
}

View file

@ -20,6 +20,7 @@
#include "JurisdictionMap.h"
#include "OctreePacketData.h"
#include "SequenceNumberStats.h"
#include "OctalCode.h"
#define GREENISH 0x40ff40d0
#define YELLOWISH 0xffef40c0
@ -143,10 +144,10 @@ public:
const char* getItemValue(Item item);
/// Returns OctCode for root element of the jurisdiction of this particular octree server
unsigned char* getJurisdictionRoot() const { return _jurisdictionRoot; }
OctalCodePtr getJurisdictionRoot() const { return _jurisdictionRoot; }
/// Returns list of OctCodes for end elements of the jurisdiction of this particular octree server
const std::vector<unsigned char*>& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; }
const OctalCodePtrList& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; }
bool isMoving() const { return _isMoving; }
bool isFullScene() const { return _isFullScene; }
@ -277,8 +278,8 @@ private:
static const int MAX_ITEM_VALUE_LENGTH = 128;
char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH];
unsigned char* _jurisdictionRoot;
std::vector<unsigned char*> _jurisdictionEndNodes;
OctalCodePtr _jurisdictionRoot;
std::vector<OctalCodePtr> _jurisdictionEndNodes;
};
/// Map between element IDs and their reported OctreeSceneStats. Typically used by classes that need to know which elements sent

View file

@ -264,6 +264,10 @@ void CharacterController::setState(State desiredState, const char* reason) {
#else
void CharacterController::setState(State desiredState) {
#endif
if (!_flyingAllowed && desiredState == State::Hover) {
desiredState = State::InAir;
}
if (desiredState != _state) {
#ifdef DEBUG_STATE_CHANGE
qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason;
@ -644,3 +648,13 @@ bool CharacterController::getRigidBodyLocation(glm::vec3& avatarRigidBodyPositio
avatarRigidBodyRotation = bulletToGLM(worldTrans.getRotation());
return true;
}
void CharacterController::setFlyingAllowed(bool value) {
if (_flyingAllowed != value) {
_flyingAllowed = value;
if (!_flyingAllowed && _state == State::Hover) {
SET_STATE(State::InAir, "flying not allowed");
}
}
}

View file

@ -110,6 +110,9 @@ public:
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
void setFlyingAllowed(bool value);
protected:
#ifdef DEBUG_STATE_CHANGE
void setState(State state, const char* reason);
@ -172,6 +175,8 @@ protected:
btRigidBody* _rigidBody { nullptr };
uint32_t _pendingFlags { 0 };
uint32_t _previousFlags { 0 };
bool _flyingAllowed { true };
};
#endif // hifi_CharacterControllerInterface_h

View file

@ -404,6 +404,11 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
assert(_body);
assert(entityTreeIsLocked());
if (_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()) {
// don't send updates for someone else's avatarEntities
return false;
}
if (_entity->actionDataNeedsTransmit()) {
return true;
}
@ -547,8 +552,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()...";
#endif
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties);
_entity->setLastBroadcast(usecTimestampNow());
EntityTreeElementPointer element = _entity->getElement();
EntityTreePointer tree = element ? element->getTree() : nullptr;
properties.setClientOnly(_entity->getClientOnly());
properties.setOwningAvatarID(_entity->getOwningAvatarID());
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, tree, id, properties);
_entity->setLastBroadcast(now);
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
// if they've changed.
@ -559,8 +570,13 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
entityDescendant->setLastBroadcast(usecTimestampNow());
newQueryCubeProperties.setClientOnly(entityDescendant->getClientOnly());
newQueryCubeProperties.setOwningAvatarID(entityDescendant->getOwningAvatarID());
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, tree,
descendant->getID(), newQueryCubeProperties);
entityDescendant->setLastBroadcast(now);
}
}
});

View file

@ -217,6 +217,12 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re
} else if (entity->isReadyToComputeShape()) {
ShapeInfo shapeInfo;
entity->computeShapeInfo(shapeInfo);
int numPoints = shapeInfo.getMaxNumPoints();
if (numPoints > MAX_HULL_POINTS) {
qWarning() << "convex hull with" << numPoints
<< "points for entity" << entity->getName()
<< "at" << entity->getPosition() << " will be reduced";
}
btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo);
if (shape) {
EntityMotionState* motionState = new EntityMotionState(shape, entity);

View file

@ -10,6 +10,7 @@
//
#include <glm/gtx/norm.hpp>
#include <BulletCollision/CollisionShapes/btShapeHull.h>
#include <SharedUtil.h> // for MILLIMETERS_PER_METER
@ -64,6 +65,22 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector<glm::vec3>& poin
correctedPoint = (points[i] - center) * relativeScale + center;
hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false);
}
if (points.size() > MAX_HULL_POINTS) {
// create hull approximation
btShapeHull shapeHull(hull);
shapeHull.buildHull(margin);
// we cannot copy Bullet shapes so we must create a new one...
btConvexHullShape* newHull = new btConvexHullShape();
const btVector3* newPoints = shapeHull.getVertexPointer();
for (int i = 0; i < shapeHull.numVertices(); ++i) {
newHull->addPoint(newPoints[i], false);
}
// ...and delete the old one
delete hull;
hull = newHull;
}
hull->recalcLocalAabb();
return hull;
}

View file

@ -18,10 +18,8 @@ namespace controller {
class InputPlugin : public Plugin {
public:
virtual bool isJointController() const = 0;
virtual void pluginFocusOutEvent() = 0;
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) = 0;
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0;
};

View file

@ -100,10 +100,6 @@ bool Procedural::parseUrl(const QUrl& shaderUrl) {
return false;
}
if (_shaderUrl == shaderUrl) {
return true;
}
_shaderUrl = shaderUrl;
_shaderDirty = true;

View file

@ -149,17 +149,12 @@ void DeferredLightingEffect::prepare(RenderArgs* args) {
batch.setFramebuffer(deferredFbo);
// Clear Color, Depth and Stencil
// Clear Color, Depth and Stencil for deferred buffer
batch.clearFramebuffer(
gpu::Framebuffer::BUFFER_COLOR0 |
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 |
gpu::Framebuffer::BUFFER_DEPTH |
gpu::Framebuffer::BUFFER_STENCIL,
vec4(vec3(0), 1), 1.0, 0.0, true);
// clear the normal and specular buffers
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
const float MAX_SPECULAR_EXPONENT = 128.0f;
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR2, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT), true);
vec4(vec3(0), 0), 1.0, 0.0, true);
});
}
@ -469,9 +464,10 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo
batch.setInputBuffer(0, mesh->getVertexBuffer());
batch.setInputFormat(mesh->getVertexFormat());
auto& part = mesh->getPartBuffer().get<model::Mesh::Part>();
batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex);
{
auto& part = mesh->getPartBuffer().get<model::Mesh::Part>(0);
batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex);
}
}
}
}
@ -548,14 +544,12 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
// Stencil test all the light passes for objects pixels only, not the background
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
if (lightVolume) {
state->setCullMode(gpu::State::CULL_BACK);
// No need for z test since the depth buffer is not bound state->setDepthTest(true, false, gpu::LESS_EQUAL);
// TODO: We should bind the true depth buffer both as RT and texture for the depth test
state->setDepthTest(true, false, gpu::LESS_EQUAL);
// TODO: We should use DepthClamp and avoid changing geometry for inside /outside cases
state->setDepthClampEnable(true);
// additive blending
state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
@ -662,10 +656,13 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
_spotLightMesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(sizeof(unsigned short) * indices, (gpu::Byte*) indexData), gpu::Element::INDEX_UINT16));
delete[] indexData;
model::Mesh::Part part(0, indices, 0, model::Mesh::TRIANGLES);
//DEBUG: model::Mesh::Part part(0, indices, 0, model::Mesh::LINE_STRIP);
_spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL));
std::vector<model::Mesh::Part> parts;
parts.push_back(model::Mesh::Part(0, indices, 0, model::Mesh::TRIANGLES));
parts.push_back(model::Mesh::Part(0, indices, 0, model::Mesh::LINE_STRIP)); // outline version
_spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
}
return _spotLightMesh;
}

View file

@ -52,17 +52,19 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const
batch.setFramebuffer(fbo);
batch.clearFramebuffer(
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
vec4(vec3(1.0, 1.0, 1.0), 1.0), 1.0, 0, true);
vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true);
batch.setProjectionTransform(shadow.getProjection());
batch.setViewTransform(shadow.getView());
auto shadowPipeline = _shapePlumber->pickPipeline(args, ShapeKey());
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, ShapeKey::Builder().withSkinned());
args->_pipeline = shadowPipeline;
batch.setPipeline(shadowPipeline->pipeline);
std::vector<ShapeKey> skinnedShapeKeys{};
// Iterate through all inShapes and render the unskinned
args->_pipeline = shadowPipeline;
batch.setPipeline(shadowPipeline->pipeline);
for (auto items : inShapes) {
if (items.first.isSkinned()) {
skinnedShapeKeys.push_back(items.first);
@ -71,6 +73,7 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const
}
}
// Reiterate to render the skinned
args->_pipeline = shadowSkinnedPipeline;
batch.setPipeline(shadowSkinnedPipeline->pipeline);
for (const auto& key : skinnedShapeKeys) {

View file

@ -87,7 +87,8 @@ float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) {
float evalShadowAttenuation(vec4 position) {
vec4 shadowTexcoord = evalShadowTexcoord(position);
if (shadowTexcoord.x < 0.0 || shadowTexcoord.x > 1.0 ||
shadowTexcoord.y < 0.0 || shadowTexcoord.y > 1.0) {
shadowTexcoord.y < 0.0 || shadowTexcoord.y > 1.0 ||
shadowTexcoord.z < 0.0 || shadowTexcoord.z > 1.0) {
// If a point is not in the map, do not attenuate
return 1.0;
}

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ScriptCache.h"
#include <QCoreApplication>
#include <QEventLoop>
#include <QNetworkAccessManager>
@ -20,7 +22,7 @@
#include <assert.h>
#include <SharedUtil.h>
#include "ScriptCache.h"
#include "ScriptEngines.h"
#include "ScriptEngineLogging.h"
ScriptCache::ScriptCache(QObject* parent) {
@ -78,22 +80,25 @@ void ScriptCache::scriptDownloaded() {
QList<ScriptUser*> scriptUsers = _scriptUsers.values(url);
_scriptUsers.remove(url);
if (req->getResult() == ResourceRequest::Success) {
auto scriptContents = req->getData();
_scriptCache[url] = scriptContents;
lock.unlock();
qCDebug(scriptengine) << "Done downloading script at:" << url.toString();
if (!DependencyManager::get<ScriptEngines>()->isStopped()) {
if (req->getResult() == ResourceRequest::Success) {
auto scriptContents = req->getData();
_scriptCache[url] = scriptContents;
lock.unlock();
qCDebug(scriptengine) << "Done downloading script at:" << url.toString();
foreach(ScriptUser* user, scriptUsers) {
user->scriptContentsAvailable(url, scriptContents);
}
} else {
lock.unlock();
qCWarning(scriptengine) << "Error loading script from URL " << url;
foreach(ScriptUser* user, scriptUsers) {
user->errorInLoadingScript(url);
foreach(ScriptUser* user, scriptUsers) {
user->scriptContentsAvailable(url, scriptContents);
}
} else {
lock.unlock();
qCWarning(scriptengine) << "Error loading script from URL " << url;
foreach(ScriptUser* user, scriptUsers) {
user->errorInLoadingScript(url);
}
}
}
req->deleteLater();
}
@ -162,9 +167,11 @@ void ScriptCache::scriptContentAvailable() {
}
}
foreach(contentAvailableCallback thisCallback, allCallbacks) {
thisCallback(url.toString(), scriptContent, true, success);
}
req->deleteLater();
}
if (!DependencyManager::get<ScriptEngines>()->isStopped()) {
foreach(contentAvailableCallback thisCallback, allCallbacks) {
thisCallback(url.toString(), scriptContent, true, success);
}
}
}

View file

@ -294,13 +294,6 @@ void ScriptEngine::waitTillDoneRunning() {
auto startedWaiting = usecTimestampNow();
while (workerThread->isRunning()) {
// NOTE: This will be called on the main application thread from stopAllScripts.
// The application thread will need to continue to process events, because
// the scripts will likely need to marshall messages across to the main thread, e.g.
// if they access Settings or Menu in any of their shutdown code. So:
// Process events for the main application thread, allowing invokeMethod calls to pass between threads.
QCoreApplication::processEvents();
// If the final evaluation takes too long, then tell the script engine to stop running
auto elapsedUsecs = usecTimestampNow() - startedWaiting;
static const auto MAX_SCRIPT_EVALUATION_TIME = USECS_PER_SECOND;
@ -326,6 +319,17 @@ void ScriptEngine::waitTillDoneRunning() {
}
}
// NOTE: This will be called on the main application thread from stopAllScripts.
// The application thread will need to continue to process events, because
// the scripts will likely need to marshall messages across to the main thread, e.g.
// if they access Settings or Menu in any of their shutdown code. So:
// Process events for the main application thread, allowing invokeMethod calls to pass between threads.
QCoreApplication::processEvents();
// In some cases (debugging), processEvents may give the thread enough time to shut down, so recheck it.
if (!thread()) {
break;
}
// Avoid a pure busy wait
QThread::yieldCurrentThread();
}

View file

@ -256,7 +256,7 @@ QVariantList ScriptEngines::getRunning() {
}
static const QString SETTINGS_KEY = "Settings";
static const QString SETTINGS_KEY = "RunningScripts";
void ScriptEngines::loadDefaultScripts() {
QUrl defaultScriptsLoc = defaultScriptsLocation();
@ -281,6 +281,43 @@ void ScriptEngines::loadScripts() {
// loads all saved scripts
Settings settings;
// START of backward compatibility code
// This following if statement is only meant to update the settings file still using the old setting key.
// If you read that comment and it has been more than a couple months since it was merged,
// then by all means, feel free to remove it.
if (!settings.childGroups().contains(SETTINGS_KEY)) {
qWarning() << "Detected old script settings config, loading from previous location";
const QString oldKey = "Settings";
// Load old scripts array from settings
int size = settings.beginReadArray(oldKey);
for (int i = 0; i < size; ++i) {
settings.setArrayIndex(i);
QString string = settings.value("script").toString();
if (!string.isEmpty()) {
loadScript(string);
}
}
settings.endArray();
// Cleanup old scripts array from settings
settings.beginWriteArray(oldKey);
for (int i = 0; i < size; ++i) {
settings.setArrayIndex(i);
settings.remove("");
}
settings.endArray();
settings.beginGroup(oldKey);
settings.remove("size");
settings.endGroup();
return;
}
// END of backward compatibility code
int size = settings.beginReadArray(SETTINGS_KEY);
for (int i = 0; i < size; ++i) {
settings.setArrayIndex(i);

View file

@ -68,6 +68,7 @@ public:
// Called at shutdown time
void shutdownScripting();
bool isStopped() const { return _isStopped; }
signals:
void scriptCountChanged();
@ -86,7 +87,6 @@ protected:
void onScriptEngineLoaded(const QString& scriptFilename);
void onScriptEngineError(const QString& scriptFilename);
void launchScriptEngine(ScriptEngine* engine);
bool isStopped() const { return _isStopped; }
QReadWriteLock _scriptEnginesHashLock;
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;

View file

@ -140,11 +140,11 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
_async = async;
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager.hasValidAccessToken()) {
if (accountManager->hasValidAccessToken()) {
QUrlQuery urlQuery(_url.query());
urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token);
urlQuery.addQueryItem("access_token", accountManager->getAccountInfo().getAccessToken().token);
_url.setQuery(urlQuery);
}

View file

@ -435,8 +435,8 @@ void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& seconda
#ifndef NDEBUG
const float MIN_LENGTH_SQUARED = 1.0e-6f;
#endif
assert(fabsf(glm::length2(primaryAxis) > MIN_LENGTH_SQUARED));
assert(fabsf(glm::length2(secondaryAxis) > MIN_LENGTH_SQUARED));
assert(glm::length2(primaryAxis) > MIN_LENGTH_SQUARED);
assert(glm::length2(secondaryAxis) > MIN_LENGTH_SQUARED);
uAxisOut = glm::normalize(primaryAxis);
glm::vec3 normSecondary = glm::normalize(secondaryAxis);

View file

@ -304,14 +304,18 @@ bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* po
return true;
}
unsigned char* hexStringToOctalCode(const QString& input) {
OctalCodePtr createOctalCodePtr(size_t size) {
return OctalCodePtr(new unsigned char[size], std::default_delete<unsigned char[]>());
}
OctalCodePtr hexStringToOctalCode(const QString& input) {
const int HEX_NUMBER_BASE = 16;
const int HEX_BYTE_SIZE = 2;
int stringIndex = 0;
int byteArrayIndex = 0;
// allocate byte array based on half of string length
unsigned char* bytes = new unsigned char[(input.length()) / HEX_BYTE_SIZE];
auto bytes = createOctalCodePtr(input.length() / HEX_BYTE_SIZE);
// loop through the string - 2 bytes at a time converting
// it to decimal equivalent and store in byte array
@ -321,15 +325,14 @@ unsigned char* hexStringToOctalCode(const QString& input) {
if (!ok) {
break;
}
bytes[byteArrayIndex] = (unsigned char)value;
bytes.get()[byteArrayIndex] = (unsigned char)value;
stringIndex += HEX_BYTE_SIZE;
byteArrayIndex++;
}
// something went wrong
if (!ok) {
delete[] bytes;
return NULL;
return nullptr;
}
return bytes;
}

View file

@ -12,9 +12,11 @@
#ifndef hifi_OctalCode_h
#define hifi_OctalCode_h
#include <string.h>
#include <vector>
#include <QString>
#include <memory>
const int BITS_IN_OCTAL = 3;
const int NUMBER_OF_COLORS = 3; // RGB!
const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes
@ -22,6 +24,9 @@ const int RED_INDEX = 0;
const int GREEN_INDEX = 1;
const int BLUE_INDEX = 2;
using OctalCodePtr = std::shared_ptr<unsigned char>;
using OctalCodePtrList = std::vector<OctalCodePtr>;
void printOctalCode(const unsigned char* octalCode);
size_t bytesRequiredForCodeLength(unsigned char threeBitCodes);
int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode);
@ -57,7 +62,8 @@ typedef enum {
OctalCodeComparison compareOctalCodes(const unsigned char* code1, const unsigned char* code2);
OctalCodePtr createOctalCodePtr(size_t size);
QString octalCodeToHexString(const unsigned char* octalCode);
unsigned char* hexStringToOctalCode(const QString& input);
OctalCodePtr hexStringToOctalCode(const QString& input);
#endif // hifi_OctalCode_h

View file

@ -97,7 +97,7 @@ namespace Setting {
}
void Interface::deinit() {
if (privateInstance) {
if (_isInitialized && privateInstance) {
// Save value to disk
save();

View file

@ -99,6 +99,18 @@ uint32_t ShapeInfo::getNumSubShapes() const {
}
return 1;
}
int ShapeInfo::getMaxNumPoints() const {
int numPoints = 0;
for (int i = 0; i < _points.size(); ++i) {
int n = _points[i].size();
if (n > numPoints) {
numPoints = n;
}
}
return numPoints;
}
float ShapeInfo::computeVolume() const {
const float DEFAULT_VOLUME = 1.0f;
float volume = DEFAULT_VOLUME;

View file

@ -22,6 +22,10 @@
const float MIN_SHAPE_OFFSET = 0.001f; // offsets less than 1mm will be ignored
// Bullet has a mesh generation util for convex shapes that we used to
// trim convex hulls with many points down to only 42 points.
const int MAX_HULL_POINTS = 42;
enum ShapeType {
SHAPE_TYPE_NONE,
SHAPE_TYPE_BOX,
@ -61,6 +65,7 @@ public:
void clearPoints () { _points.clear(); }
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
int getMaxNumPoints() const;
float computeVolume() const;

View file

@ -23,7 +23,7 @@ void StreamUtil::dump(std::ostream& s, const QByteArray& buffer) {
while (i < buffer.size()) {
for(int j = 0; i < buffer.size() && j < row_size; ++j) {
char byte = buffer[i];
s << hex_digits[(byte >> 4) & 0x0f] << hex_digits[byte & 0x0f] << " ";
s << hex_digits[(byte >> 4) & 0x0f] << hex_digits[byte & 0x0f] << ' ';
++i;
}
s << "\n";
@ -31,21 +31,21 @@ void StreamUtil::dump(std::ostream& s, const QByteArray& buffer) {
}
std::ostream& operator<<(std::ostream& s, const glm::vec3& v) {
s << "<" << v.x << " " << v.y << " " << v.z << ">";
s << '(' << v.x << ' ' << v.y << ' ' << v.z << ')';
return s;
}
std::ostream& operator<<(std::ostream& s, const glm::quat& q) {
s << "<" << q.x << " " << q.y << " " << q.z << " " << q.w << ">";
s << '(' << q.x << ' ' << q.y << ' ' << q.z << ' ' << q.w << ')';
return s;
}
std::ostream& operator<<(std::ostream& s, const glm::mat4& m) {
s << "[";
s << '[';
for (int j = 0; j < 4; ++j) {
s << " " << m[0][j] << " " << m[1][j] << " " << m[2][j] << " " << m[3][j] << ";";
s << ' ' << m[0][j] << ' ' << m[1][j] << ' ' << m[2][j] << ' ' << m[3][j] << ';';
}
s << " ]";
s << " ]";
return s;
}
@ -69,54 +69,37 @@ QDataStream& operator>>(QDataStream& in, glm::quat& quaternion) {
#include <QDebug>
QDebug& operator<<(QDebug& dbg, const glm::vec2& v) {
dbg.nospace() << "{type='glm::vec2'"
", x=" << v.x <<
", y=" << v.y <<
"}";
dbg.nospace() << '(' << v.x << ", " << v.y << ')';
return dbg;
}
QDebug& operator<<(QDebug& dbg, const glm::vec3& v) {
dbg.nospace() << "{type='glm::vec3'"
", x=" << v.x <<
", y=" << v.y <<
", z=" << v.z <<
"}";
dbg.nospace() << '(' << v.x << ", " << v.y << ", " << v.z << ')';
return dbg;
}
QDebug& operator<<(QDebug& dbg, const glm::vec4& v) {
dbg.nospace() << "{type='glm::vec4'"
", x=" << v.x <<
", y=" << v.y <<
", z=" << v.z <<
", w=" << v.w <<
"}";
dbg.nospace() << '(' << v.x << ", " << v.y << ", " << v.z << ", " << v.w << ')';
return dbg;
}
QDebug& operator<<(QDebug& dbg, const glm::quat& q) {
dbg.nospace() << "{type='glm::quat'"
", x=" << q.x <<
", y=" << q.y <<
", z=" << q.z <<
", w=" << q.w <<
"}";
dbg.nospace() << '(' << q.x << ", " << q.y << ", " << q.z << ", " << q.w << ')';
return dbg;
}
QDebug& operator<<(QDebug& dbg, const glm::mat4& m) {
dbg.nospace() << "{type='glm::mat4', [";
dbg.nospace() << '[';
for (int j = 0; j < 4; ++j) {
dbg << ' ' << m[0][j] << ' ' << m[1][j] << ' ' << m[2][j] << ' ' << m[3][j] << ';';
}
return dbg << " ]}";
return dbg << " ]";
}
QDebug& operator<<(QDebug& dbg, const QVariantHash& v) {
dbg.nospace() << "[";
dbg.nospace() << "[ ";
for (QVariantHash::const_iterator it = v.constBegin(); it != v.constEnd(); it++) {
dbg << it.key() << ":" << it.value();
dbg << it.key() << ':' << it.value();
}
return dbg << " ]";
}

View file

@ -53,8 +53,8 @@ QString fixupHifiUrl(const QString& urlString) {
QUrl url(urlString);
QUrlQuery query(url);
if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) {
AccountManager& accountManager = AccountManager::getInstance();
query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager.getAccountInfo().getAccessToken().token);
auto accountManager = DependencyManager::get<AccountManager>();
query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager->getAccountInfo().getAccessToken().token);
url.setQuery(query.query());
return url.toString();
}
@ -590,6 +590,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
// let the parent class do it's work
bool result = OffscreenQmlSurface::eventFilter(originalDestination, event);
// Check if this is a key press/release event that might need special attention
auto type = event->type();
if (type != QEvent::KeyPress && type != QEvent::KeyRelease) {
@ -597,7 +598,8 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
}
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
bool& pressed = _pressedKeys[keyEvent->key()];
auto key = keyEvent->key();
bool& pressed = _pressedKeys[key];
// Keep track of which key press events the QML has accepted
if (result && QEvent::KeyPress == type) {
@ -607,7 +609,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
// QML input elements absorb key press, but apparently not key release.
// therefore we want to ensure that key release events for key presses that were
// accepted by the QML layer are suppressed
if (!result && type == QEvent::KeyRelease && pressed) {
if (type == QEvent::KeyRelease && pressed) {
pressed = false;
return true;
}

View file

@ -84,16 +84,16 @@ void Tooltip::requestHyperlinkImage() {
// should the network link be removed from UI at a later date.
// we possibly have a valid place name - so ask the API for the associated info
AccountManager& accountManager = AccountManager::getInstance();
auto accountManager = DependencyManager::get<AccountManager>();
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "handleAPIResponse";
accountManager.sendRequest(GET_PLACE.arg(_title),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation,
callbackParams);
accountManager->sendRequest(GET_PLACE.arg(_title),
AccountManagerAuth::None,
QNetworkAccessManager::GetOperation,
callbackParams);
}
}
}

View file

@ -6,8 +6,11 @@
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
#
set(TARGET_NAME hifiNeuron)
setup_hifi_plugin(Script Qml Widgets)
link_hifi_libraries(shared controllers ui plugins input-plugins)
target_neuron()
if (APPLE OR WIN32)
set(TARGET_NAME hifiNeuron)
setup_hifi_plugin(Script Qml Widgets)
link_hifi_libraries(shared controllers ui plugins input-plugins)
target_neuron()
endif()

View file

@ -25,9 +25,7 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
#define __OS_XUN__ 1
#define BOOL int
#ifdef HAVE_NEURON
#include <NeuronDataReader.h>
#endif
const QString NeuronPlugin::NAME = "Neuron";
const QString NeuronPlugin::NEURON_ID_STRING = "Perception Neuron";
@ -166,69 +164,6 @@ static controller::StandardPoseChannel neuronJointIndexToPoseIndexMap[NeuronJoin
static glm::vec3 rightHandThumb1DefaultAbsTranslation(-2.155500650405884, -0.7610001564025879, 2.685631036758423);
static glm::vec3 leftHandThumb1DefaultAbsTranslation(2.1555817127227783, -0.7603635787963867, 2.6856393814086914);
// default translations (cm)
static glm::vec3 neuronJointTranslations[NeuronJointIndex::Size] = {
{131.901, 95.6602, -27.9815},
{-9.55907, -1.58772, 0.0760284},
{0.0144232, -41.4683, -0.105322},
{1.59348, -41.5875, -0.557237},
{9.72077, -1.68926, -0.280643},
{0.0886684, -43.1586, -0.0111596},
{-2.98473, -44.0517, 0.0694456},
{0.110967, 16.3959, 0.140463},
{0.0500451, 10.0238, 0.0731921},
{0.061568, 10.4352, 0.0583075},
{0.0500606, 10.0217, 0.0711083},
{0.0317731, 10.7176, 0.0779325},
{-0.0204253, 9.71067, 0.131734},
{-3.24245, 7.13584, 0.185638},
{-13.0885, -0.0877601, 0.176065},
{-27.2674, 0.0688724, 0.0272146},
{-26.7673, 0.0301916, 0.0102847},
{-2.56017, 0.195537, 3.20968},
{-3.78796, 0, 0},
{-2.63141, 0, 0},
{-3.31579, 0.522947, 2.03495},
{-5.36589, -0.0939789, 1.02771},
{-3.72278, 0, 0},
{-2.11074, 0, 0},
{-3.47874, 0.532042, 0.778358},
{-5.32194, -0.0864, 0.322863},
{-4.06232, 0, 0},
{-2.54653, 0, 0},
{-3.46131, 0.553263, -0.132632},
{-4.76716, -0.0227368, -0.492632},
{-3.54073, 0, 0},
{-2.45634, 0, 0},
{-3.25137, 0.482779, -1.23613},
{-4.25937, -0.0227368, -1.12168},
{-2.83528, 0, 0},
{-1.79166, 0, 0},
{3.25624, 7.13148, -0.131575},
{13.149, -0.052598, -0.125076},
{27.2903, 0.00282644, -0.0181535},
{26.6602, 0.000969969, -0.0487599},
{2.56017, 0.195537, 3.20968},
{3.78796, 0, 0},
{2.63141, 0, 0},
{3.31579, 0.522947, 2.03495},
{5.36589, -0.0939789, 1.02771},
{3.72278, 0, 0},
{2.11074, 0, 0},
{3.47874, 0.532042, 0.778358},
{5.32194, -0.0864, 0.322863},
{4.06232, 0, 0},
{2.54653, 0, 0},
{3.46131, 0.553263, -0.132632},
{4.76716, -0.0227368, -0.492632},
{3.54073, 0, 0},
{2.45634, 0, 0},
{3.25137, 0.482779, -1.23613},
{4.25937, -0.0227368, -1.12168},
{2.83528, 0, 0},
{1.79166, 0, 0}
};
static controller::StandardPoseChannel neuronJointIndexToPoseIndex(NeuronJointIndex i) {
assert(i >= 0 && i < NeuronJointIndex::Size);
if (i >= 0 && i < NeuronJointIndex::Size) {
@ -307,16 +242,13 @@ static const char* controllerJointName(controller::StandardPoseChannel i) {
// convert between YXZ neuron euler angles in degrees to quaternion
// this is the default setting in the Axis Neuron server.
static quat eulerToQuat(vec3 euler) {
static quat eulerToQuat(const vec3& e) {
// euler.x and euler.y are swaped, WTF.
glm::vec3 e = glm::vec3(euler.y, euler.x, euler.z) * RADIANS_PER_DEGREE;
return (glm::angleAxis(e.y, Vectors::UNIT_Y) *
glm::angleAxis(e.x, Vectors::UNIT_X) *
glm::angleAxis(e.z, Vectors::UNIT_Z));
return (glm::angleAxis(e.x * RADIANS_PER_DEGREE, Vectors::UNIT_Y) *
glm::angleAxis(e.y * RADIANS_PER_DEGREE, Vectors::UNIT_X) *
glm::angleAxis(e.z * RADIANS_PER_DEGREE, Vectors::UNIT_Z));
}
#ifdef HAVE_NEURON
//
// neuronDataReader SDK callback functions
//
@ -355,21 +287,6 @@ void FrameDataReceivedCallback(void* context, SOCKET_REF sender, BvhDataHeaderEx
// copy the data
memcpy(&(neuronPlugin->_joints[0]), data, sizeof(NeuronPlugin::NeuronJoint) * NUM_JOINTS);
} else {
qCWarning(inputplugins) << "NeuronPlugin: unsuported binary format, please enable displacements";
// enter mutex
std::lock_guard<std::mutex> guard(neuronPlugin->_jointsMutex);
if (neuronPlugin->_joints.size() != NeuronJointIndex::Size) {
neuronPlugin->_joints.resize(NeuronJointIndex::Size, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } });
}
for (int i = 0; i < NeuronJointIndex::Size; i++) {
neuronPlugin->_joints[i].euler = glm::vec3();
neuronPlugin->_joints[i].pos = neuronJointTranslations[i];
}
}
} else {
static bool ONCE = false;
@ -435,26 +352,19 @@ static void SocketStatusChangedCallback(void* context, SOCKET_REF sender, Socket
qCDebug(inputplugins) << "NeuronPlugin: socket status = " << message;
}
#endif // #ifdef HAVE_NEURON
//
// NeuronPlugin
//
bool NeuronPlugin::isSupported() const {
#ifdef HAVE_NEURON
// Because it's a client/server network architecture, we can't tell
// if the neuron is actually connected until we connect to the server.
return true;
#else
return false;
#endif
}
bool NeuronPlugin::activate() {
InputPlugin::activate();
#ifdef HAVE_NEURON
// register with userInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
userInputMapper->registerDevice(_inputDevice);
@ -480,13 +390,9 @@ bool NeuronPlugin::activate() {
BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode);
return true;
}
#else
return false;
#endif
}
void NeuronPlugin::deactivate() {
#ifdef HAVE_NEURON
// unregister from userInputMapper
if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) {
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
@ -499,10 +405,9 @@ void NeuronPlugin::deactivate() {
}
InputPlugin::deactivate();
#endif
}
void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
std::vector<NeuronJoint> joints;
{
// lock and copy
@ -548,16 +453,23 @@ QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const {
void NeuronPlugin::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const std::vector<NeuronPlugin::NeuronJoint>& joints, const std::vector<NeuronPlugin::NeuronJoint>& prevJoints) {
for (size_t i = 0; i < joints.size(); i++) {
int poseIndex = neuronJointIndexToPoseIndex((NeuronJointIndex)i);
glm::vec3 linearVel, angularVel;
glm::vec3 pos = joints[i].pos;
glm::quat rot = eulerToQuat(joints[i].euler);
const glm::vec3& pos = joints[i].pos;
const glm::vec3& rotEuler = joints[i].euler;
if (Vectors::ZERO == pos && Vectors::ZERO == rotEuler) {
_poseStateMap[poseIndex] = controller::Pose();
continue;
}
glm::quat rot = eulerToQuat(rotEuler);
if (i < prevJoints.size()) {
linearVel = (pos - (prevJoints[i].pos * METERS_PER_CENTIMETER)) / deltaTime; // m/s
// quat log imaginary part points along the axis of rotation, with length of one half the angle of rotation.
glm::quat d = glm::log(rot * glm::inverse(eulerToQuat(prevJoints[i].euler)));
angularVel = glm::vec3(d.x, d.y, d.z) / (0.5f * deltaTime); // radians/s
}
int poseIndex = neuronJointIndexToPoseIndex((NeuronJointIndex)i);
_poseStateMap[poseIndex] = controller::Pose(pos, rot, linearVel, angularVel);
}

View file

@ -27,7 +27,6 @@ public:
// Plugin functions
virtual bool isSupported() const override;
virtual bool isJointController() const override { return true; }
virtual const QString& getName() const override { return NAME; }
const QString& getID() const override { return NEURON_ID_STRING; }
@ -35,7 +34,7 @@ public:
virtual void deactivate() override;
virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
virtual void saveSettings() const override;
virtual void loadSettings() override;
@ -56,7 +55,7 @@ protected:
// Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override;
virtual QString getDefaultMappingConfig() const override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override {};
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override {};
virtual void focusOutEvent() override {};
void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const std::vector<NeuronPlugin::NeuronJoint>& joints, const std::vector<NeuronPlugin::NeuronJoint>& prevJoints);

View file

@ -15,7 +15,6 @@
const float CONTROLLER_THRESHOLD = 0.3f;
#ifdef HAVE_SDL2
const float MAX_AXIS = 32768.0f;
Joystick::Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController) :
@ -27,19 +26,15 @@ Joystick::Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameControl
}
#endif
Joystick::~Joystick() {
closeJoystick();
}
void Joystick::closeJoystick() {
#ifdef HAVE_SDL2
SDL_GameControllerClose(_sdlGameController);
#endif
}
void Joystick::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
void Joystick::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
for (auto axisState : _axisStateMap) {
if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) {
_axisStateMap[axisState.first] = 0.0f;
@ -52,8 +47,6 @@ void Joystick::focusOutEvent() {
_buttonPressedMap.clear();
};
#ifdef HAVE_SDL2
void Joystick::handleAxisEvent(const SDL_ControllerAxisEvent& event) {
SDL_GameControllerAxis axis = (SDL_GameControllerAxis) event.axis;
_axisStateMap[makeInput((controller::StandardAxisChannel)axis).getChannel()] = (float)event.value / MAX_AXIS;
@ -69,8 +62,6 @@ void Joystick::handleButtonEvent(const SDL_ControllerButtonEvent& event) {
}
}
#endif
controller::Input::NamedVector Joystick::getAvailableInputs() const {
using namespace controller;
static const Input::NamedVector availableInputs{

View file

@ -15,10 +15,8 @@
#include <qobject.h>
#include <qvector.h>
#ifdef HAVE_SDL2
#include <SDL.h>
#undef main
#endif
#include <controllers/InputDevice.h>
#include <controllers/StandardControls.h>
@ -26,10 +24,7 @@
class Joystick : public QObject, public controller::InputDevice {
Q_OBJECT
Q_PROPERTY(QString name READ getName)
#ifdef HAVE_SDL2
Q_PROPERTY(int instanceId READ getInstanceId)
#endif
public:
using Pointer = std::shared_ptr<Joystick>;
@ -39,33 +34,25 @@ public:
// Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override;
virtual QString getDefaultMappingConfig() const override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
virtual void focusOutEvent() override;
Joystick() : InputDevice("GamePad") {}
~Joystick();
#ifdef HAVE_SDL2
Joystick(SDL_JoystickID instanceId, SDL_GameController* sdlGameController);
#endif
void closeJoystick();
#ifdef HAVE_SDL2
void handleAxisEvent(const SDL_ControllerAxisEvent& event);
void handleButtonEvent(const SDL_ControllerButtonEvent& event);
#endif
#ifdef HAVE_SDL2
int getInstanceId() const { return _instanceId; }
#endif
private:
#ifdef HAVE_SDL2
SDL_GameController* _sdlGameController;
SDL_Joystick* _sdlJoystick;
SDL_JoystickID _instanceId;
#endif
};
#endif // hifi_Joystick_h

View file

@ -16,7 +16,6 @@
#include "SDL2Manager.h"
#ifdef HAVE_SDL2
static_assert(
(int)controller::A == (int)SDL_CONTROLLER_BUTTON_A &&
(int)controller::B == (int)SDL_CONTROLLER_BUTTON_B &&
@ -40,28 +39,16 @@ static_assert(
(int)controller::LT == (int)SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
(int)controller::RT == (int)SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
"SDL2 equvalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
#endif
const QString SDL2Manager::NAME = "SDL2";
#ifdef HAVE_SDL2
SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
return SDL_JoystickInstanceID(joystick);
}
#endif
SDL2Manager::SDL2Manager() :
#ifdef HAVE_SDL2
_openJoysticks(),
#endif
_isInitialized(false)
{
}
void SDL2Manager::init() {
#ifdef HAVE_SDL2
bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER) == 0);
if (initSuccess) {
@ -88,66 +75,50 @@ void SDL2Manager::init() {
else {
qDebug() << "Error initializing SDL2 Manager";
}
#endif
}
void SDL2Manager::deinit() {
#ifdef HAVE_SDL2
_openJoysticks.clear();
SDL_Quit();
#endif
}
bool SDL2Manager::activate() {
InputPlugin::activate();
#ifdef HAVE_SDL2
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
for (auto joystick : _openJoysticks) {
userInputMapper->registerDevice(joystick);
emit joystickAdded(joystick.get());
}
return true;
#else
return false;
#endif
}
void SDL2Manager::deactivate() {
#ifdef HAVE_SDL2
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
for (auto joystick : _openJoysticks) {
userInputMapper->removeDevice(joystick->getDeviceID());
emit joystickRemoved(joystick.get());
}
#endif
InputPlugin::deactivate();
}
bool SDL2Manager::isSupported() const {
#ifdef HAVE_SDL2
return true;
#else
return false;
#endif
}
void SDL2Manager::pluginFocusOutEvent() {
#ifdef HAVE_SDL2
for (auto joystick : _openJoysticks) {
joystick->focusOutEvent();
}
#endif
}
void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
#ifdef HAVE_SDL2
void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
if (_isInitialized) {
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
for (auto joystick : _openJoysticks) {
joystick->update(deltaTime, inputCalibrationData, jointsCaptured);
joystick->update(deltaTime, inputCalibrationData);
}
PerformanceTimer perfTimer("SDL2Manager::update");
@ -197,5 +168,4 @@ void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrati
}
}
}
#endif
}

Some files were not shown because too many files have changed in this diff Show more