diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index f99c1d280e..c6ab0285ea 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -50,6 +50,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : _hostname(), _webAuthenticationStateSet(), _cookieSessionHash(), + _automaticNetworkingSetting(), _settingsManager() { LogUtils::init(); @@ -327,17 +328,17 @@ void DomainServer::setupAutomaticNetworking() { return; } - QString automaticNetworkValue = + _automaticNetworkingSetting = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); - if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || - automaticNetworkValue == FULL_AUTOMATIC_NETWORKING_VALUE) { + if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || + _automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); const QUuid& domainID = nodeList->getSessionUUID(); if (!domainID.isNull()) { - qDebug() << "domain-server" << automaticNetworkValue << "automatic networking enabled for ID" + qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID" << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; @@ -347,7 +348,7 @@ void DomainServer::setupAutomaticNetworking() { QTimer* dynamicIPTimer = new QTimer(this); connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); - if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { + if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); // send public socket changes to the data server so nodes can find us at our new IP @@ -361,11 +362,11 @@ void DomainServer::setupAutomaticNetworking() { iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); // call our sendHeartbeaToIceServer immediately anytime a local or public socket changes - connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); - connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); + connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer); + connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHeartbeatToIceServer); - // tell the data server which type of automatic networking we are using - updateNetworkingInfoWithDataServer(automaticNetworkValue); + // send our heartbeat to data server so it knows what our network settings are + sendHeartbeatToDataServer(); } // attempt to update our sockets now @@ -378,8 +379,17 @@ void DomainServer::setupAutomaticNetworking() { return; } } else { - updateNetworkingInfoWithDataServer(automaticNetworkValue); + sendHeartbeatToDataServer(); } + + qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; + + // no matter the auto networking settings we should heartbeat to the data-server every 15s + const int DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS = 15 * 1000; + + QTimer* dataHeartbeatTimer = new QTimer(this); + connect(dataHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToDataServer); + dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS); } void DomainServer::loginFailed() { @@ -1081,10 +1091,10 @@ QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) { const QString DOMAIN_UPDATE_AUTOMATIC_NETWORKING_KEY = "automatic_networking"; void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) { - updateNetworkingInfoWithDataServer(IP_ONLY_AUTOMATIC_NETWORKING_VALUE, newPublicSockAddr.getAddress().toString()); + updateDomainInDataServer(newPublicSockAddr.getAddress().toString()); } -void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, const QString& networkAddress) { +void DomainServer::updateDomainInDataServer(const QString& networkAddress) { const QString DOMAIN_UPDATE = "/api/v1/domains/%1"; const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID(); @@ -1097,9 +1107,7 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, domainObject[PUBLIC_NETWORK_ADDRESS_KEY] = networkAddress; } - qDebug() << "Updating automatic networking setting in domain-server to" << newSetting; - - domainObject[AUTOMATIC_NETWORKING_KEY] = newSetting; + domainObject[AUTOMATIC_NETWORKING_KEY] = _automaticNetworkingSetting; QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson())); @@ -1112,11 +1120,11 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, // todo: have data-web respond with ice-server hostname to use void DomainServer::performICEUpdates() { - sendHearbeatToIceServer(); + sendHeartbeatToIceServer(); sendICEPingPackets(); } -void DomainServer::sendHearbeatToIceServer() { +void DomainServer::sendHeartbeatToIceServer() { const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr("ice.highfidelity.io", ICE_SERVER_DEFAULT_PORT); LimitedNodeList::getInstance()->sendHeartbeatToIceServer(ICE_SERVER_SOCK_ADDR); } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 5e4da00601..e5f321639c 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -66,7 +66,8 @@ private slots: void requestCurrentPublicSocketViaSTUN(); void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr); void performICEUpdates(); - void sendHearbeatToIceServer(); + void sendHeartbeatToDataServer() { updateDomainInDataServer(); } + void sendHeartbeatToIceServer(); void sendICEPingPackets(); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); @@ -76,7 +77,7 @@ private: bool optionallySetupAssignmentPayment(); void setupAutomaticNetworking(); - void updateNetworkingInfoWithDataServer(const QString& newSetting, const QString& networkAddress = QString()); + void updateDomainInDataServer(const QString& networkAddress = QString()); void processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr); void processICEHeartbeatResponse(const QByteArray& packet); @@ -150,6 +151,8 @@ private: QHash _connectingICEPeers; QHash _connectedICEPeers; + QString _automaticNetworkingSetting; + DomainServerSettingsManager _settingsManager; }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 623631d5e5..b468f37f33 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1269,6 +1269,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe _isPushing = false; float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f); + glm::vec3 newLocalVelocity = localVelocity; float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + fabsf(_driveKeys[UP] - _driveKeys[DOWN]); @@ -1285,31 +1286,47 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe if (directionLength > EPSILON) { direction /= directionLength; - // Compute the target keyboard velocity (which ramps up slowly, and damps very quickly) - // the max magnitude of which depends on what we're doing: - float motorSpeed = glm::length(_keyboardMotorVelocity); - float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED; - float speedGrowthTimescale = 2.0f; - float speedIncreaseFactor = 1.8f; - motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - const float maxBoostSpeed = _scale * MAX_BOOST_SPEED; - if (motorSpeed < maxBoostSpeed) { - // an active keyboard motor should never be slower than this - float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; - motorSpeed += MIN_AVATAR_SPEED * boostCoefficient; - motorEfficiency += (1.0f - motorEfficiency) * boostCoefficient; - } else if (motorSpeed > finalMaxMotorSpeed) { - motorSpeed = finalMaxMotorSpeed; + if (hasFloor) { + // we're walking --> simple exponential decay toward target walk speed + const float WALK_ACCELERATION_TIMESCALE = 0.7f; // seconds to decrease delta to 1/e + _keyboardMotorVelocity = MAX_WALKING_SPEED * direction; + motorEfficiency = glm::clamp(deltaTime / WALK_ACCELERATION_TIMESCALE, 0.0f, 1.0f); + + } else { + // we're flying --> more complex curve + float motorSpeed = glm::length(_keyboardMotorVelocity); + float finalMaxMotorSpeed = _scale * MAX_KEYBOARD_MOTOR_SPEED; + float speedGrowthTimescale = 2.0f; + float speedIncreaseFactor = 1.8f; + motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; + const float maxBoostSpeed = _scale * MAX_BOOST_SPEED; + if (motorSpeed < maxBoostSpeed) { + // an active keyboard motor should never be slower than this + float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; + motorSpeed += MIN_AVATAR_SPEED * boostCoefficient; + motorEfficiency += (1.0f - motorEfficiency) * boostCoefficient; + } else if (motorSpeed > finalMaxMotorSpeed) { + motorSpeed = finalMaxMotorSpeed; + } + _keyboardMotorVelocity = motorSpeed * direction; } - _keyboardMotorVelocity = motorSpeed * direction; _isPushing = true; } + newLocalVelocity = localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity); } else { _keyboardMotorVelocity = glm::vec3(0.0f); + newLocalVelocity = (1.0f - motorEfficiency) * localVelocity; + if (hasFloor && !_wasPushing) { + float speed = glm::length(newLocalVelocity); + if (speed > MIN_AVATAR_SPEED) { + // add small constant friction to help avatar drift to a stop sooner at low speeds + const float CONSTANT_FRICTION_DECELERATION = MIN_AVATAR_SPEED / 0.20f; + newLocalVelocity *= (speed - timescale * CONSTANT_FRICTION_DECELERATION) / speed; + } + } } - // apply keyboard motor - return localVelocity + motorEfficiency * (_keyboardMotorVelocity - localVelocity); + return newLocalVelocity; } glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVelocity) {