Merge remote-tracking branch 'upstream/master' into burp2
|
@ -46,8 +46,14 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION,
|
||||
"run single assignment client of given type", "type");
|
||||
QString typeDescription = "run single assignment client of given type\n# | Type\n============================";
|
||||
for (Assignment::Type type = Assignment::FirstType;
|
||||
type != Assignment::AllTypes;
|
||||
type = static_cast<Assignment::Type>(static_cast<int>(type) + 1)) {
|
||||
typeDescription.append(QStringLiteral("\n%1 | %2").arg(QString::number(type), Assignment::typeToString(type)));
|
||||
}
|
||||
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION, typeDescription, "type");
|
||||
|
||||
parser.addOption(clientTypeOption);
|
||||
|
||||
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||
|
|
|
@ -477,7 +477,7 @@ void EntityServer::startDynamicDomainVerification() {
|
|||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location");
|
||||
QJsonObject request;
|
||||
request["certificate_id"] = i.key();
|
||||
|
|
|
@ -94,7 +94,7 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
|||
root.insert(requestSubobjectKey, subobject);
|
||||
QJsonDocument doc { root };
|
||||
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + metaversePath };
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL().toString() + metaversePath };
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
@ -420,7 +420,7 @@ bool DomainServer::optionallySetupOAuth() {
|
|||
|
||||
// if we don't have an oauth provider URL then we default to the default node auth url
|
||||
if (_oauthProviderURL.isEmpty()) {
|
||||
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
}
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
@ -945,7 +945,7 @@ void DomainServer::createStaticAssignmentsForType(Assignment::Type type, const Q
|
|||
|
||||
void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Assignment::Type>& excludedTypes) {
|
||||
// enumerate over all assignment types and see if we've already excluded it
|
||||
for (Assignment::Type defaultedType = Assignment::AudioMixerType;
|
||||
for (Assignment::Type defaultedType = Assignment::FirstType;
|
||||
defaultedType != Assignment::AllTypes;
|
||||
defaultedType = static_cast<Assignment::Type>(static_cast<int>(defaultedType) + 1)) {
|
||||
if (!excludedTypes.contains(defaultedType) && defaultedType != Assignment::AgentType) {
|
||||
|
@ -2159,7 +2159,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
QJsonDocument doc(root);
|
||||
|
||||
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/v1/places/" + place_id };
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/v1/places/" + place_id };
|
||||
|
||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ void IceServer::requestDomainPublicKey(const QUuid& domainID) {
|
|||
// send a request to the metaverse API for the public key for this domain
|
||||
auto& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL };
|
||||
QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL() };
|
||||
QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID));
|
||||
publicKeyURL.setPath(publicKeyPath);
|
||||
|
||||
|
|
|
@ -52,7 +52,11 @@ Item {
|
|||
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
|
||||
}
|
||||
|
||||
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
||||
var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
||||
if(!isNaN(newWidth)) {
|
||||
parent.width = root.width = newWidth;
|
||||
}
|
||||
|
||||
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ Rectangle {
|
|||
} else if (walletStatus === 2) {
|
||||
if (root.activeView !== "passphraseModal") {
|
||||
root.activeView = "passphraseModal";
|
||||
UserActivityLogger.commercePassphraseEntry("marketplace checkout");
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
authSuccessStep();
|
||||
|
|
|
@ -54,6 +54,7 @@ Rectangle {
|
|||
} else if (walletStatus === 2) {
|
||||
if (root.activeView !== "passphraseModal") {
|
||||
root.activeView = "passphraseModal";
|
||||
UserActivityLogger.commercePassphraseEntry("marketplace purchases");
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") {
|
||||
|
|
|
@ -25,10 +25,6 @@ Item {
|
|||
|
||||
id: root;
|
||||
|
||||
SecurityImageModel {
|
||||
id: securityImageModel;
|
||||
}
|
||||
|
||||
// Username Text
|
||||
RalewayRegular {
|
||||
id: usernameText;
|
||||
|
|
|
@ -50,8 +50,10 @@ Item {
|
|||
submitPassphraseInputButton.enabled = true;
|
||||
if (!isAuthenticated) {
|
||||
errorText.text = "Authentication failed - please try again.";
|
||||
UserActivityLogger.commercePassphraseAuthenticationStatus("auth failure");
|
||||
} else {
|
||||
sendSignalToParent({method: 'authSuccess'});;
|
||||
sendSignalToParent({method: 'authSuccess'});
|
||||
UserActivityLogger.commercePassphraseAuthenticationStatus("auth success");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -336,6 +338,7 @@ Item {
|
|||
text: "Cancel"
|
||||
onClicked: {
|
||||
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
||||
UserActivityLogger.commercePassphraseAuthenticationStatus("passphrase modal cancelled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,6 @@ Item {
|
|||
id: root;
|
||||
property bool justSubmitted: false;
|
||||
|
||||
SecurityImageModel {
|
||||
id: securityImageModel;
|
||||
}
|
||||
|
||||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
|
||||
|
@ -213,4 +209,8 @@ Item {
|
|||
securityImageSubmitButton.enabled = true;
|
||||
securityImageSubmitButton.text = "Submit";
|
||||
}
|
||||
|
||||
function initModel() {
|
||||
securityImageSelection.initModel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,29 +15,28 @@ import QtQuick 2.5
|
|||
|
||||
ListModel {
|
||||
id: root;
|
||||
ListElement{
|
||||
sourcePath: "images/01.jpg"
|
||||
securityImageEnumValue: 1;
|
||||
|
||||
function initModel() {
|
||||
var array = [];
|
||||
while (array.length < 6) {
|
||||
// We currently have 34 security images to choose from
|
||||
var randomNumber = Math.floor(Math.random() * 34) + 1;
|
||||
if (array.indexOf(randomNumber) > -1) {
|
||||
continue;
|
||||
}
|
||||
array[array.length] = randomNumber;
|
||||
}
|
||||
|
||||
var modelElement;
|
||||
|
||||
for (var i = 0; i < 6; i++) {
|
||||
modelElement = { "sourcePath":"images/" + addLeadingZero(array[i]) + ".jpg", "securityImageEnumValue": (i + 1) }
|
||||
root.insert(i, modelElement);
|
||||
}
|
||||
}
|
||||
ListElement{
|
||||
sourcePath: "images/02.jpg"
|
||||
securityImageEnumValue: 2;
|
||||
}
|
||||
ListElement{
|
||||
sourcePath: "images/03.jpg"
|
||||
securityImageEnumValue: 3;
|
||||
}
|
||||
ListElement{
|
||||
sourcePath: "images/04.jpg"
|
||||
securityImageEnumValue: 4;
|
||||
}
|
||||
ListElement{
|
||||
sourcePath: "images/05.jpg"
|
||||
securityImageEnumValue: 5;
|
||||
}
|
||||
ListElement{
|
||||
sourcePath: "images/06.jpg"
|
||||
securityImageEnumValue: 6;
|
||||
|
||||
function addLeadingZero(n) {
|
||||
return n < 10 ? '0' + n : '' + n;
|
||||
}
|
||||
|
||||
function getImagePathFromImageID(imageID) {
|
||||
|
|
|
@ -95,6 +95,10 @@ Item {
|
|||
function getSelectedImageIndex() {
|
||||
return gridModel.get(securityImageGrid.currentIndex).securityImageEnumValue;
|
||||
}
|
||||
|
||||
function initModel() {
|
||||
gridModel.initModel();
|
||||
}
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
|
|
|
@ -57,6 +57,7 @@ Rectangle {
|
|||
} else if (walletStatus === 2) {
|
||||
if (root.activeView !== "passphraseModal") {
|
||||
root.activeView = "passphraseModal";
|
||||
UserActivityLogger.commercePassphraseEntry("wallet app");
|
||||
}
|
||||
} else if (walletStatus === 3) {
|
||||
root.activeView = "walletHome";
|
||||
|
@ -82,10 +83,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
SecurityImageModel {
|
||||
id: securityImageModel;
|
||||
}
|
||||
|
||||
HifiCommerceCommon.CommerceLightbox {
|
||||
id: lightboxPopup;
|
||||
visible: false;
|
||||
|
@ -342,6 +339,7 @@ Rectangle {
|
|||
passphraseChange.clearPassphraseFields();
|
||||
passphraseChange.resetSubmitButton();
|
||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,6 +236,7 @@ Item {
|
|||
height: 50;
|
||||
text: "Set Up Wallet";
|
||||
onClicked: {
|
||||
securityImageSelection.initModel();
|
||||
root.activeView = "step_2";
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 35 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/07.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/08.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/09.jpg
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/10.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/11.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/12.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/13.jpg
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/14.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/15.jpg
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/16.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/17.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/18.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/19.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/20.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/21.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/22.jpg
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/23.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/24.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/25.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/26.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/27.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/28.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/29.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/30.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/31.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/32.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/33.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/34.jpg
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
interface/resources/qml/js/Utils.jsc
Normal file
|
@ -971,7 +971,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
// 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->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL());
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
|
@ -1496,6 +1496,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
}
|
||||
});
|
||||
|
||||
connect(getEntities()->getTree().get(), &EntityTree::deletingEntity, [=](const EntityItemID& entityItemID) {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr;
|
||||
if (myAvatar) {
|
||||
myAvatar->clearAvatarEntity(entityItemID);
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard focus handling for Web overlays.
|
||||
auto overlays = &(qApp->getOverlays());
|
||||
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
||||
|
@ -3222,8 +3230,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||
_keysPressed.remove(event->key());
|
||||
|
||||
|
@ -4848,8 +4854,7 @@ void Application::update(float deltaTime) {
|
|||
if (_physicsEnabled) {
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "PreStep");
|
||||
|
||||
PerformanceTimer perfTimer("updateStates)");
|
||||
PerformanceTimer perfTimer("preStep)");
|
||||
static VectorOfMotionStates motionStates;
|
||||
_entitySimulation->getObjectsToRemoveFromPhysics(motionStates);
|
||||
_physicsEngine->removeObjects(motionStates);
|
||||
|
@ -4882,22 +4887,22 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "Step");
|
||||
PerformanceTimer perfTimer("stepSimulation");
|
||||
PerformanceTimer perfTimer("step");
|
||||
getEntities()->getTree()->withWriteLock([&] {
|
||||
_physicsEngine->stepSimulation();
|
||||
});
|
||||
}
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "PostStep");
|
||||
PerformanceTimer perfTimer("harvestChanges");
|
||||
PerformanceTimer perfTimer("postStep");
|
||||
if (_physicsEngine->hasOutgoingChanges()) {
|
||||
// grab the collision events BEFORE handleOutgoingChanges() because at this point
|
||||
// we have a better idea of which objects we own or should own.
|
||||
auto& collisionEvents = _physicsEngine->getCollisionEvents();
|
||||
|
||||
getEntities()->getTree()->withWriteLock([&] {
|
||||
PROFILE_RANGE(simulation_physics, "Harvest");
|
||||
PerformanceTimer perfTimer("handleOutgoingChanges");
|
||||
PROFILE_RANGE(simulation_physics, "HandleChanges");
|
||||
PerformanceTimer perfTimer("handleChanges");
|
||||
|
||||
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
|
||||
_entitySimulation->handleChangedMotionStates(outgoingChanges);
|
||||
|
@ -4908,17 +4913,15 @@ void Application::update(float deltaTime) {
|
|||
});
|
||||
|
||||
if (!_aboutToQuit) {
|
||||
// handleCollisionEvents() AFTER handleOutgoinChanges()
|
||||
// handleCollisionEvents() AFTER handleOutgoingChanges()
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "CollisionEvents");
|
||||
PerformanceTimer perfTimer("entities");
|
||||
avatarManager->handleCollisionEvents(collisionEvents);
|
||||
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
||||
// deadlock.)
|
||||
_entitySimulation->handleCollisionEvents(collisionEvents);
|
||||
}
|
||||
|
||||
PROFILE_RANGE(simulation_physics, "UpdateEntities");
|
||||
// NOTE: the getEntities()->update() call below will wait for lock
|
||||
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
||||
getEntities()->update(true); // update the models...
|
||||
|
@ -4929,7 +4932,8 @@ void Application::update(float deltaTime) {
|
|||
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
||||
if (PerformanceTimer::isActive() &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
|
||||
_physicsEngine->harvestPerformanceStats();
|
||||
}
|
||||
|
@ -7506,4 +7510,9 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) {
|
|||
_avatarOverrideUrl = url;
|
||||
_saveAvatarOverrideUrl = save;
|
||||
}
|
||||
|
||||
void Application::saveNextPhysicsStats(QString filename) {
|
||||
_physicsEngine->saveNextPhysicsStats(filename);
|
||||
}
|
||||
|
||||
#include "Application.moc"
|
||||
|
|
|
@ -280,6 +280,7 @@ public:
|
|||
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
|
||||
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
||||
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
||||
void saveNextPhysicsStats(QString filename);
|
||||
|
||||
signals:
|
||||
void svoImportRequested(const QString& url);
|
||||
|
@ -432,6 +433,7 @@ private slots:
|
|||
|
||||
void handleSandboxStatus(QNetworkReply* reply);
|
||||
void switchDisplayMode();
|
||||
|
||||
private:
|
||||
static void initDisplay();
|
||||
void init();
|
||||
|
|
|
@ -645,7 +645,8 @@ Menu::Menu() {
|
|||
// Developer > Timing >>>
|
||||
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
||||
MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false,
|
||||
qApp, SLOT(enablePerfStats(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
||||
|
|
|
@ -81,6 +81,7 @@ const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amaz
|
|||
const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||
const float MyAvatar::ZOOM_MAX = 25.0f;
|
||||
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
||||
|
||||
MyAvatar::MyAvatar(QThread* thread) :
|
||||
Avatar(thread),
|
||||
|
@ -670,6 +671,11 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||
|
||||
bool hasSensorToWorldScaleChanged = false;
|
||||
if (fabsf(getSensorToWorldScale() - sensorToWorldScale) > MIN_SCALE_CHANGED_DELTA) {
|
||||
hasSensorToWorldScaleChanged = true;
|
||||
}
|
||||
|
||||
lateUpdatePalms();
|
||||
|
||||
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||
|
@ -678,9 +684,13 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
}
|
||||
|
||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||
|
||||
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
||||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||
|
||||
if (hasSensorToWorldScaleChanged) {
|
||||
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
|
@ -1405,6 +1415,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||
_headBoneSet.clear();
|
||||
emit skeletonChanged();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1440,6 +1451,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
|||
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
||||
}
|
||||
markIdentityDataChanged();
|
||||
|
||||
}
|
||||
|
||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
#include "MySkeletonModel.h"
|
||||
|
||||
#include <avatars-renderer/Avatar.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "AnimUtil.h"
|
||||
|
||||
|
||||
MySkeletonModel::MySkeletonModel(Avatar* owningAvatar, QObject* parent) : SkeletonModel(owningAvatar, parent) {
|
||||
}
|
||||
|
@ -30,6 +33,39 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle
|
|||
};
|
||||
}
|
||||
|
||||
static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
||||
glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor();
|
||||
glm::vec3 hipsPos = extractTranslation(hipsMat);
|
||||
glm::quat hipsRot = glmExtractRotation(hipsMat);
|
||||
|
||||
glm::mat4 avatarToWorldMat = myAvatar->getTransform().getMatrix();
|
||||
glm::mat4 worldToSensorMat = glm::inverse(myAvatar->getSensorToWorldMatrix());
|
||||
glm::mat4 avatarToSensorMat = worldToSensorMat * avatarToWorldMat;
|
||||
|
||||
// dampen hips rotation, by mixing it with the avatar orientation in sensor space
|
||||
const float MIX_RATIO = 0.5f;
|
||||
hipsRot = safeLerp(glmExtractRotation(avatarToSensorMat), hipsRot, MIX_RATIO);
|
||||
|
||||
if (isFlying) {
|
||||
// rotate the hips back to match the flying animation.
|
||||
|
||||
const float TILT_ANGLE = 0.523f;
|
||||
const glm::quat tiltRot = glm::angleAxis(TILT_ANGLE, transformVectorFast(avatarToSensorMat, -Vectors::UNIT_X));
|
||||
|
||||
glm::vec3 headPos;
|
||||
int headIndex = myAvatar->getJointIndex("Head");
|
||||
if (headIndex != -1) {
|
||||
headPos = transformPoint(avatarToSensorMat, myAvatar->getAbsoluteJointTranslationInObjectFrame(headIndex));
|
||||
} else {
|
||||
headPos = transformPoint(myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition());
|
||||
}
|
||||
hipsRot = tiltRot * hipsRot;
|
||||
hipsPos = headPos + tiltRot * (hipsPos - headPos);
|
||||
}
|
||||
|
||||
return AnimPose(hipsRot * Quaternions::Y_180, hipsPos);
|
||||
}
|
||||
|
||||
// Called within Model::simulate call, below.
|
||||
void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
|
@ -124,6 +160,39 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
}
|
||||
}
|
||||
|
||||
// if hips are not under direct control, estimate the hips position.
|
||||
if (avatarHeadPose.isValid() && !params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips]) {
|
||||
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS);
|
||||
|
||||
if (!_prevHipsValid) {
|
||||
AnimPose hips = computeHipsInSensorFrame(myAvatar, isFlying);
|
||||
_prevHips = hips;
|
||||
}
|
||||
|
||||
AnimPose hips = computeHipsInSensorFrame(myAvatar, isFlying);
|
||||
|
||||
// smootly lerp hips, in sensorframe, with different coeff for horiz and vertical translation.
|
||||
const float ROT_ALPHA = 0.9f;
|
||||
const float TRANS_HORIZ_ALPHA = 0.9f;
|
||||
const float TRANS_VERT_ALPHA = 0.1f;
|
||||
float hipsY = hips.trans().y;
|
||||
hips.trans() = lerp(hips.trans(), _prevHips.trans(), TRANS_HORIZ_ALPHA);
|
||||
hips.trans().y = lerp(hipsY, _prevHips.trans().y, TRANS_VERT_ALPHA);
|
||||
hips.rot() = safeLerp(hips.rot(), _prevHips.rot(), ROT_ALPHA);
|
||||
|
||||
_prevHips = hips;
|
||||
_prevHipsValid = true;
|
||||
|
||||
glm::mat4 invRigMat = glm::inverse(myAvatar->getTransform().getMatrix() * Matrices::Y_180);
|
||||
AnimPose sensorToRigPose(invRigMat * myAvatar->getSensorToWorldMatrix());
|
||||
|
||||
params.primaryControllerPoses[Rig::PrimaryControllerType_Hips] = sensorToRigPose * hips;
|
||||
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips] = true;
|
||||
|
||||
} else {
|
||||
_prevHipsValid = false;
|
||||
}
|
||||
|
||||
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
||||
|
||||
// pass detailed torso k-dops to rig.
|
||||
|
|
|
@ -25,6 +25,9 @@ public:
|
|||
|
||||
private:
|
||||
void updateFingers();
|
||||
|
||||
AnimPose _prevHips; // sensor frame
|
||||
bool _prevHipsValid { false };
|
||||
};
|
||||
|
||||
#endif // hifi_MySkeletonModel_h
|
||||
|
|
|
@ -130,7 +130,7 @@ QString amountString(const QString& label, const QString&color, const QJsonValue
|
|||
return result + QString("</font>");
|
||||
}
|
||||
|
||||
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace/items/";
|
||||
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||
void Ledger::historySuccess(QNetworkReply& reply) {
|
||||
// here we send a historyResult with some extra stuff in it
|
||||
// Namely, the styled text we'd like to show. The issue is the
|
||||
|
|
|
@ -315,7 +315,6 @@ Wallet::Wallet() {
|
|||
}
|
||||
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
emit walletStatusResult(status);
|
||||
});
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
@ -491,6 +490,7 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
}
|
||||
if (_publicKeys.count() > 0) {
|
||||
// we _must_ be authenticated if the publicKeys are there
|
||||
DependencyManager::get<WalletScriptingInterface>()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -503,6 +503,7 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
// be sure to add the public key so we don't do this over and over
|
||||
_publicKeys.push_back(publicKey.toBase64());
|
||||
DependencyManager::get<WalletScriptingInterface>()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -801,15 +802,12 @@ void Wallet::account() {
|
|||
|
||||
void Wallet::getWalletStatus() {
|
||||
auto walletScriptingInterface = DependencyManager::get<WalletScriptingInterface>();
|
||||
uint status;
|
||||
|
||||
if (DependencyManager::get<AccountManager>()->isLoggedIn()) {
|
||||
// This will set account info for the wallet, allowing us to decrypt and display the security image.
|
||||
account();
|
||||
} else {
|
||||
status = (uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN;
|
||||
emit walletStatusResult(status);
|
||||
walletScriptingInterface->setWalletStatus(status);
|
||||
walletScriptingInterface->setWalletStatus((uint)WalletStatus::WALLET_STATUS_NOT_LOGGED_IN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ QNetworkRequest createNetworkRequest() {
|
|||
|
||||
QNetworkRequest request;
|
||||
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath(USER_ACTIVITY_URL);
|
||||
|
||||
request.setUrl(requestURL);
|
||||
|
|
|
@ -23,10 +23,10 @@ static const float WEB_STYLUS_LENGTH = 0.2f;
|
|||
static const float TABLET_MIN_HOVER_DISTANCE = -0.1f;
|
||||
static const float TABLET_MAX_HOVER_DISTANCE = 0.1f;
|
||||
static const float TABLET_MIN_TOUCH_DISTANCE = -0.1f;
|
||||
static const float TABLET_MAX_TOUCH_DISTANCE = 0.01f;
|
||||
static const float TABLET_MAX_TOUCH_DISTANCE = 0.005f;
|
||||
|
||||
static const float HOVER_HYSTERESIS = 0.01f;
|
||||
static const float TOUCH_HYSTERESIS = 0.02f;
|
||||
static const float TOUCH_HYSTERESIS = 0.001f;
|
||||
|
||||
static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
||||
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <shared/FileUtils.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <Trace.h>
|
||||
#include <StatTracker.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <StatTracker.h>
|
||||
#include <Trace.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
|
@ -141,6 +142,15 @@ void TestScriptingInterface::endTraceEvent(QString name) {
|
|||
tracing::traceEvent(trace_test(), name, tracing::DurationEnd);
|
||||
}
|
||||
|
||||
void TestScriptingInterface::savePhysicsSimulationStats(QString originalPath) {
|
||||
QString path = FileUtils::replaceDateTimeTokens(originalPath);
|
||||
path = FileUtils::computeDocumentPath(path);
|
||||
if (!FileUtils::canCreateFile(path)) {
|
||||
return;
|
||||
}
|
||||
qApp->saveNextPhysicsStats(path);
|
||||
}
|
||||
|
||||
void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) {
|
||||
PROFILE_RANGE(script, name);
|
||||
fn.call();
|
||||
|
|
|
@ -71,6 +71,11 @@ public slots:
|
|||
|
||||
void endTraceEvent(QString name);
|
||||
|
||||
/**jsdoc
|
||||
* Write detailed timing stats of next physics stepSimulation() to filename
|
||||
*/
|
||||
void savePhysicsSimulationStats(QString filename);
|
||||
|
||||
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
||||
|
||||
private:
|
||||
|
|
|
@ -22,3 +22,8 @@ void WalletScriptingInterface::refreshWalletStatus() {
|
|||
auto wallet = DependencyManager::get<Wallet>();
|
||||
wallet->getWalletStatus();
|
||||
}
|
||||
|
||||
void WalletScriptingInterface::setWalletStatus(const uint& status) {
|
||||
_walletStatus = status;
|
||||
emit DependencyManager::get<Wallet>()->walletStatusResult(status);
|
||||
}
|
|
@ -39,7 +39,9 @@ public:
|
|||
|
||||
Q_INVOKABLE void refreshWalletStatus();
|
||||
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
|
||||
void setWalletStatus(const uint& status) { _walletStatus = status; }
|
||||
// setWalletStatus() should never be made Q_INVOKABLE. If it were,
|
||||
// scripts could cause the Wallet to incorrectly report its status.
|
||||
void setWalletStatus(const uint& status);
|
||||
|
||||
signals:
|
||||
void walletStatusChanged();
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
bool forwardEnabled() { return _forwardEnabled; }
|
||||
bool useFeed() { return _useFeed; }
|
||||
void setUseFeed(bool useFeed) { if (_useFeed != useFeed) { _useFeed = useFeed; emit useFeedChanged(); } }
|
||||
QString metaverseServerUrl() { return NetworkingConstants::METAVERSE_SERVER_URL.toString(); }
|
||||
QString metaverseServerUrl() { return NetworkingConstants::METAVERSE_SERVER_URL().toString(); }
|
||||
|
||||
signals:
|
||||
void backEnabledChanged();
|
||||
|
|
|
@ -78,6 +78,8 @@ bool Stats::includeTimingRecord(const QString& name) {
|
|||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||
} else if (name.startsWith("/paintGL/")) {
|
||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||
} else if (name.startsWith("step/")) {
|
||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -289,7 +289,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
|||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||
QJsonObject request;
|
||||
request["certificate_id"] = entityProperties.getCertificateID();
|
||||
|
@ -359,7 +359,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
|||
}
|
||||
}
|
||||
|
||||
static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace/items/";
|
||||
static const QString MARKETPLACE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||
|
||||
void ContextOverlayInterface::openMarketplace() {
|
||||
// lets open the tablet and go to the current item in
|
||||
|
|
|
@ -1641,9 +1641,17 @@ void Rig::initAnimGraph(const QUrl& url) {
|
|||
// load the anim graph
|
||||
_animLoader.reset(new AnimNodeLoader(url));
|
||||
_animLoading = true;
|
||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) {
|
||||
std::weak_ptr<AnimSkeleton> weakSkeletonPtr = _animSkeleton;
|
||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) {
|
||||
_animNode = nodeIn;
|
||||
_animNode->setSkeleton(_animSkeleton);
|
||||
|
||||
// abort load if the previous skeleton was deleted.
|
||||
auto sharedSkeletonPtr = weakSkeletonPtr.lock();
|
||||
if (!sharedSkeletonPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
_animNode->setSkeleton(sharedSkeletonPtr);
|
||||
|
||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||
// restore the user animation we had before reset.
|
||||
|
@ -1651,6 +1659,7 @@ void Rig::initAnimGraph(const QUrl& url) {
|
|||
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
||||
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
|
||||
}
|
||||
|
||||
// restore the role animations we had before reset.
|
||||
for (auto& roleAnimState : _roleAnimStates) {
|
||||
auto roleState = roleAnimState.second;
|
||||
|
|
|
@ -31,7 +31,7 @@ class AnimInverseKinematics;
|
|||
// Rig instances are reentrant.
|
||||
// However only specific methods thread-safe. Noted below.
|
||||
|
||||
class Rig : public QObject, public std::enable_shared_from_this<Rig> {
|
||||
class Rig : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct StateHandler {
|
||||
|
|
|
@ -96,9 +96,13 @@ void SoundProcessor::run() {
|
|||
QByteArray outputAudioByteArray;
|
||||
|
||||
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||
if (sampleRate != 0) {
|
||||
downSample(outputAudioByteArray, sampleRate);
|
||||
if (sampleRate == 0) {
|
||||
qCDebug(audio) << "Unsupported WAV file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unsupported WAV file type");
|
||||
return;
|
||||
}
|
||||
|
||||
downSample(outputAudioByteArray, sampleRate);
|
||||
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||
// check if this was a stereo raw file
|
||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||
|
|
|
@ -251,10 +251,10 @@ void EntityTreeRenderer::shutdown() {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||
PROFILE_RANGE_EX(simulation_physics, "Add", 0xffff00ff, (uint64_t)_entitiesToAdd.size());
|
||||
PROFILE_RANGE_EX(simulation_physics, "AddToScene", 0xffff00ff, (uint64_t)_entitiesToAdd.size());
|
||||
PerformanceTimer pt("add");
|
||||
// Clear any expired entities
|
||||
// FIXME should be able to use std::remove_if, but it fails due to some
|
||||
// Clear any expired entities
|
||||
// FIXME should be able to use std::remove_if, but it fails due to some
|
||||
// weird compilation error related to EntityItemID assignment operators
|
||||
for (auto itr = _entitiesToAdd.begin(); _entitiesToAdd.end() != itr; ) {
|
||||
if (itr->second.expired()) {
|
||||
|
@ -272,7 +272,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
continue;
|
||||
}
|
||||
|
||||
// Path to the parent transforms is not valid,
|
||||
// Path to the parent transforms is not valid,
|
||||
// don't add to the scene graph yet
|
||||
if (!entity->isParentPathComplete()) {
|
||||
continue;
|
||||
|
@ -296,7 +296,7 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene, const ViewFrustum& view, render::Transaction& transaction) {
|
||||
PROFILE_RANGE_EX(simulation_physics, "Change", 0xffff00ff, (uint64_t)_changedEntities.size());
|
||||
PROFILE_RANGE_EX(simulation_physics, "ChangeInScene", 0xffff00ff, (uint64_t)_changedEntities.size());
|
||||
PerformanceTimer pt("change");
|
||||
std::unordered_set<EntityItemID> changedEntities;
|
||||
_changedEntitiesGuard.withWriteLock([&] {
|
||||
|
@ -402,6 +402,8 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
PerformanceTimer perfTimer("ETRupdate");
|
||||
if (_tree && !_shuttingDown) {
|
||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
||||
// here we update _currentFrame and _lastAnimated and sync with the server properties.
|
||||
tree->update(simulate);
|
||||
|
||||
// Update the rendereable entities as needed
|
||||
|
@ -736,7 +738,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
|||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||
// qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID,
|
||||
|
|
|
@ -63,13 +63,17 @@ bool ModelEntityWrapper::isModelLoaded() const {
|
|||
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
|
||||
[](EntityItem* ptr) { ptr->deleteLater(); });
|
||||
|
||||
entity->setProperties(properties);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
|
||||
ModelEntityWrapper(entityItemID),
|
||||
_dimensionsInitialized(dimensionsInitialized) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
RenderableModelEntityItem::~RenderableModelEntityItem() { }
|
||||
|
@ -464,7 +468,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
// TODO: assert we never fall in here when model not fully loaded
|
||||
//assert(_model && _model->isLoaded());
|
||||
// assert(_model && _model->isLoaded());
|
||||
|
||||
updateModelBounds();
|
||||
model->updateGeometry();
|
||||
|
@ -974,9 +978,6 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
|
|||
entity->setModel({});
|
||||
}
|
||||
|
||||
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||
if (!_animation || !_animation->isLoaded()) {
|
||||
|
@ -991,19 +992,12 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_lastAnimated) {
|
||||
_lastAnimated = usecTimestampNow();
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = usecTimestampNow();
|
||||
auto interval = now - _lastAnimated;
|
||||
_lastAnimated = now;
|
||||
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
|
||||
_currentFrame += (deltaTime * _renderAnimationProperties.getFPS());
|
||||
|
||||
{
|
||||
int animationCurrentFrame = (int)(glm::floor(_currentFrame)) % frameCount;
|
||||
// the current frame is set on the server in update() in ModelEntityItem.cpp
|
||||
int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame()));
|
||||
|
||||
// in the case where the last frame is greater than the framecount then clamp
|
||||
// it to the end of the animation until it loops around.
|
||||
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
|
||||
animationCurrentFrame = 0;
|
||||
}
|
||||
|
@ -1039,10 +1033,10 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
glm::mat4 translationMat;
|
||||
|
||||
if (allowTranslation) {
|
||||
if(index < translations.size()){
|
||||
if (index < translations.size()) {
|
||||
translationMat = glm::translate(translations[index]);
|
||||
}
|
||||
} else if (index < animationJointNames.size()){
|
||||
} else if (index < animationJointNames.size()) {
|
||||
QString jointName = fbxJoints[index].name; // Pushing this here so its not done on every entity, with the exceptions of those allowing for translation
|
||||
|
||||
if (originalFbxIndices.contains(jointName)) {
|
||||
|
@ -1317,25 +1311,17 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
if (model->getRenderItemsNeedUpdate()) {
|
||||
model->updateRenderItems();
|
||||
}
|
||||
|
||||
{
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "CheckAnimation");
|
||||
// make a copy of the animation properites
|
||||
auto newAnimationProperties = entity->getAnimationProperties();
|
||||
if (newAnimationProperties != _renderAnimationProperties) {
|
||||
withWriteLock([&] {
|
||||
_renderAnimationProperties = newAnimationProperties;
|
||||
_currentFrame = _renderAnimationProperties.getCurrentFrame();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The code to deal with the change of properties is now in ModelEntityItem.cpp
|
||||
// That is where _currentFrame and _lastAnimated were updated.
|
||||
if (_animating) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
||||
if (!jointsMapped()) {
|
||||
mapJoints(entity, model->getJointNames());
|
||||
}
|
||||
animate(entity);
|
||||
if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) {
|
||||
animate(entity);
|
||||
}
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace render { namespace entities {
|
|||
class ModelEntityRenderer;
|
||||
} }
|
||||
|
||||
//#define MODEL_ENTITY_USE_FADE_EFFECT
|
||||
// #define MODEL_ENTITY_USE_FADE_EFFECT
|
||||
class ModelEntityWrapper : public ModelEntityItem {
|
||||
using Parent = ModelEntityItem;
|
||||
friend class render::entities::ModelEntityRenderer;
|
||||
|
@ -133,7 +133,7 @@ class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem
|
|||
friend class EntityRenderer;
|
||||
|
||||
public:
|
||||
ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { }
|
||||
ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
||||
|
||||
protected:
|
||||
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
|
||||
|
@ -184,8 +184,6 @@ private:
|
|||
bool _shouldHighlight { false };
|
||||
bool _animating { false };
|
||||
uint64_t _lastAnimated { 0 };
|
||||
float _currentFrame { 0 };
|
||||
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -22,15 +22,28 @@ const float AnimationPropertyGroup::MAXIMUM_POSSIBLE_FRAME = 100000.0f;
|
|||
|
||||
bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||
return
|
||||
(a._url == b._url) &&
|
||||
|
||||
(a._currentFrame == b._currentFrame) &&
|
||||
(a._running == b._running) &&
|
||||
(a._loop == b._loop) &&
|
||||
(a._hold == b._hold) &&
|
||||
(a._firstFrame == b._firstFrame) &&
|
||||
(a._lastFrame == b._lastFrame) &&
|
||||
(a._hold == b._hold);
|
||||
(a._url == b._url);
|
||||
}
|
||||
|
||||
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||
return
|
||||
(a._currentFrame != b._currentFrame) ||
|
||||
(a._running != b._running) ||
|
||||
(a._loop != b._loop) ||
|
||||
(a._hold != b._hold) ||
|
||||
(a._firstFrame != b._firstFrame) ||
|
||||
(a._lastFrame != b._lastFrame) ||
|
||||
(a._url != b._url);
|
||||
}
|
||||
|
||||
|
||||
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
|
||||
|
@ -130,6 +143,7 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
|||
allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||
}
|
||||
|
||||
|
||||
setAllowTranslation(allowTranslation);
|
||||
setFPS(fps);
|
||||
setCurrentFrame(currentFrame);
|
||||
|
|
|
@ -89,6 +89,7 @@ public:
|
|||
|
||||
protected:
|
||||
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||
friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||
void setFromOldAnimationSettings(const QString& value);
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <Octree.h>
|
||||
#include <PhysicsHelpers.h>
|
||||
#include <Profile.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <SharedUtil.h> // usecTimestampNow()
|
||||
#include <LogHandler.h>
|
||||
|
@ -114,6 +115,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
|
|||
requestedProperties += PROP_EDITION_NUMBER;
|
||||
requestedProperties += PROP_ENTITY_INSTANCE_NUMBER;
|
||||
requestedProperties += PROP_CERTIFICATE_ID;
|
||||
requestedProperties += PROP_STATIC_CERTIFICATE_VERSION;
|
||||
|
||||
requestedProperties += PROP_NAME;
|
||||
requestedProperties += PROP_HREF;
|
||||
|
@ -271,6 +273,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, getEditionNumber());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, getEntityInstanceNumber());
|
||||
APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, getCertificateID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, getStaticCertificateVersion());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
|
||||
|
@ -819,6 +822,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber);
|
||||
READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber);
|
||||
READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID);
|
||||
READ_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
|
||||
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||
|
@ -984,6 +988,7 @@ void EntityItem::setCollisionSoundURL(const QString& value) {
|
|||
}
|
||||
|
||||
void EntityItem::simulate(const quint64& now) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Simulate");
|
||||
if (getLastSimulated() == 0) {
|
||||
setLastSimulated(now);
|
||||
}
|
||||
|
@ -1039,6 +1044,7 @@ void EntityItem::simulate(const quint64& now) {
|
|||
}
|
||||
|
||||
bool EntityItem::stepKinematicMotion(float timeElapsed) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "StepKinematicMotion");
|
||||
// get all the data
|
||||
Transform transform;
|
||||
glm::vec3 linearVelocity;
|
||||
|
@ -1249,6 +1255,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(editionNumber, getEditionNumber);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(entityInstanceNumber, getEntityInstanceNumber);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(certificateID, getCertificateID);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(staticCertificateVersion, getStaticCertificateVersion);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref);
|
||||
|
@ -1356,6 +1363,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(editionNumber, setEditionNumber);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(entityInstanceNumber, setEntityInstanceNumber);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(certificateID, setCertificateID);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(staticCertificateVersion, setStaticCertificateVersion);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
|
||||
|
@ -1626,6 +1634,10 @@ void EntityItem::setParentID(const QUuid& value) {
|
|||
newParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
|
||||
}
|
||||
|
||||
if (!oldParentID.isNull() && (oldParentID == Physics::getSessionUUID() || oldParentID == AVATAR_SELF_ID)) {
|
||||
oldParentNoBootstrapping |= Simulation::NO_BOOTSTRAPPING;
|
||||
}
|
||||
|
||||
if ((bool)(oldParentNoBootstrapping ^ newParentNoBootstrapping)) {
|
||||
if ((bool)(newParentNoBootstrapping & Simulation::NO_BOOTSTRAPPING)) {
|
||||
markDirtyFlags(Simulation::NO_BOOTSTRAPPING);
|
||||
|
@ -2783,6 +2795,7 @@ DEFINE_PROPERTY_ACCESSOR(QString, MarketplaceID, marketplaceID)
|
|||
DEFINE_PROPERTY_ACCESSOR(quint32, EditionNumber, editionNumber)
|
||||
DEFINE_PROPERTY_ACCESSOR(quint32, EntityInstanceNumber, entityInstanceNumber)
|
||||
DEFINE_PROPERTY_ACCESSOR(QString, CertificateID, certificateID)
|
||||
DEFINE_PROPERTY_ACCESSOR(quint32, StaticCertificateVersion, staticCertificateVersion)
|
||||
|
||||
uint32_t EntityItem::getDirtyFlags() const {
|
||||
uint32_t result;
|
||||
|
@ -2840,7 +2853,7 @@ void EntityItem::retrieveMarketplacePublicKey() {
|
|||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath("/api/v1/commerce/marketplace_key");
|
||||
QJsonObject request;
|
||||
networkRequest.setUrl(requestURL);
|
||||
|
|
|
@ -328,6 +328,8 @@ public:
|
|||
void setEntityInstanceNumber(const quint32&);
|
||||
QString getCertificateID() const;
|
||||
void setCertificateID(const QString& value);
|
||||
quint32 getStaticCertificateVersion() const;
|
||||
void setStaticCertificateVersion(const quint32&);
|
||||
|
||||
// TODO: get rid of users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
@ -547,6 +549,7 @@ protected:
|
|||
quint32 _editionNumber { ENTITY_ITEM_DEFAULT_EDITION_NUMBER };
|
||||
quint32 _entityInstanceNumber { ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER };
|
||||
QString _marketplaceID { ENTITY_ITEM_DEFAULT_MARKETPLACE_ID };
|
||||
quint32 _staticCertificateVersion { ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION };
|
||||
|
||||
|
||||
// NOTE: Damping is applied like this: v *= pow(1 - damping, dt)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
|
@ -325,6 +324,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_EDITION_NUMBER, editionNumber);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ENTITY_INSTANCE_NUMBER, entityInstanceNumber);
|
||||
CHECK_PROPERTY_CHANGE(PROP_CERTIFICATE_ID, certificateID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STATIC_CERTIFICATE_VERSION, staticCertificateVersion);
|
||||
|
||||
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
|
||||
|
@ -460,6 +460,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EDITION_NUMBER, editionNumber);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ENTITY_INSTANCE_NUMBER, entityInstanceNumber);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CERTIFICATE_ID, certificateID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STATIC_CERTIFICATE_VERSION, staticCertificateVersion);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
|
||||
|
@ -743,6 +744,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(editionNumber, quint32, setEditionNumber);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(entityInstanceNumber, quint32, setEntityInstanceNumber);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(certificateID, QString, setCertificateID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(staticCertificateVersion, quint32, setStaticCertificateVersion);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
|
||||
|
@ -900,6 +902,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(editionNumber);
|
||||
COPY_PROPERTY_IF_CHANGED(entityInstanceNumber);
|
||||
COPY_PROPERTY_IF_CHANGED(certificateID);
|
||||
COPY_PROPERTY_IF_CHANGED(staticCertificateVersion);
|
||||
|
||||
COPY_PROPERTY_IF_CHANGED(name);
|
||||
COPY_PROPERTY_IF_CHANGED(collisionSoundURL);
|
||||
|
@ -1090,6 +1093,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_EDITION_NUMBER, EditionNumber, editionNumber, quint32);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ENTITY_INSTANCE_NUMBER, EntityInstanceNumber, entityInstanceNumber, quint32);
|
||||
ADD_PROPERTY_TO_MAP(PROP_CERTIFICATE_ID, CertificateID, certificateID, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_STATIC_CERTIFICATE_VERSION, StaticCertificateVersion, staticCertificateVersion, quint32);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
|
||||
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
||||
|
@ -1478,6 +1482,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, properties.getEditionNumber());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, properties.getEntityInstanceNumber());
|
||||
APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, properties.getCertificateID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, properties.getStaticCertificateVersion());
|
||||
}
|
||||
|
||||
if (propertyCount > 0) {
|
||||
|
@ -1829,6 +1834,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EDITION_NUMBER, quint32, setEditionNumber);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CERTIFICATE_ID, QString, setCertificateID);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STATIC_CERTIFICATE_VERSION, quint32, setStaticCertificateVersion);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
@ -1996,6 +2002,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_editionNumberChanged = true;
|
||||
_entityInstanceNumberChanged = true;
|
||||
_certificateIDChanged = true;
|
||||
_staticCertificateVersionChanged = true;
|
||||
|
||||
_keyLight.markAllChanged();
|
||||
|
||||
|
@ -2338,6 +2345,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (certificateIDChanged()) {
|
||||
out += "certificateID";
|
||||
}
|
||||
if (staticCertificateVersionChanged()) {
|
||||
out += "staticCertificateVersion";
|
||||
}
|
||||
|
||||
if (backgroundModeChanged()) {
|
||||
out += "backgroundMode";
|
||||
|
@ -2480,6 +2490,9 @@ QByteArray EntityItemProperties::getStaticCertificateJSON() const {
|
|||
// of the entity as reviewed during the certification submission.
|
||||
|
||||
QJsonObject json;
|
||||
|
||||
quint32 staticCertificateVersion = getStaticCertificateVersion();
|
||||
|
||||
if (!getAnimation().getURL().isEmpty()) {
|
||||
json["animationURL"] = getAnimation().getURL();
|
||||
}
|
||||
|
@ -2496,7 +2509,11 @@ QByteArray EntityItemProperties::getStaticCertificateJSON() const {
|
|||
ADD_STRING_PROPERTY(marketplaceID, MarketplaceID);
|
||||
ADD_STRING_PROPERTY(modelURL, ModelURL);
|
||||
ADD_STRING_PROPERTY(script, Script);
|
||||
if (staticCertificateVersion >= 1) {
|
||||
ADD_STRING_PROPERTY(serverScripts, ServerScripts);
|
||||
}
|
||||
ADD_ENUM_PROPERTY(shapeType, ShapeType);
|
||||
ADD_INT_PROPERTY(staticCertificateVersion, StaticCertificateVersion);
|
||||
json["type"] = EntityTypes::getEntityTypeName(getType());
|
||||
|
||||
return QJsonDocument(json).toJson(QJsonDocument::Compact);
|
||||
|
|
|
@ -220,6 +220,7 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_EDITION_NUMBER, EditionNumber, editionNumber, quint32, ENTITY_ITEM_DEFAULT_EDITION_NUMBER);
|
||||
DEFINE_PROPERTY_REF(PROP_ENTITY_INSTANCE_NUMBER, EntityInstanceNumber, entityInstanceNumber, quint32, ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER);
|
||||
DEFINE_PROPERTY_REF(PROP_CERTIFICATE_ID, CertificateID, certificateID, QString, ENTITY_ITEM_DEFAULT_CERTIFICATE_ID);
|
||||
DEFINE_PROPERTY_REF(PROP_STATIC_CERTIFICATE_VERSION, StaticCertificateVersion, staticCertificateVersion, quint32, ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION);
|
||||
|
||||
// these are used when bouncing location data into and out of scripts
|
||||
DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3);
|
||||
|
@ -473,6 +474,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EditionNumber, editionNumber, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityInstanceNumber, entityInstanceNumber, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CertificateID, certificateID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, StaticCertificateVersion, staticCertificateVersion, "");
|
||||
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, HazeMode, hazeMode, "");
|
||||
|
|
|
@ -41,6 +41,7 @@ const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
|
|||
const quint32 ENTITY_ITEM_DEFAULT_EDITION_NUMBER = 0;
|
||||
const quint32 ENTITY_ITEM_DEFAULT_ENTITY_INSTANCE_NUMBER = 0;
|
||||
const QString ENTITY_ITEM_DEFAULT_CERTIFICATE_ID = QString("");
|
||||
const quint32 ENTITY_ITEM_DEFAULT_STATIC_CERTIFICATE_VERSION = 0;
|
||||
|
||||
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
|
||||
|
|
|
@ -200,6 +200,7 @@ enum EntityPropertyList {
|
|||
PROP_EDITION_NUMBER,
|
||||
PROP_ENTITY_INSTANCE_NUMBER,
|
||||
PROP_CERTIFICATE_ID,
|
||||
PROP_STATIC_CERTIFICATE_VERSION,
|
||||
|
||||
PROP_HAZE_MODE,
|
||||
|
||||
|
|
|
@ -1821,6 +1821,19 @@ glm::mat4 EntityScriptingInterface::getEntityLocalTransform(const QUuid& entityI
|
|||
return result;
|
||||
}
|
||||
|
||||
QString EntityScriptingInterface::getStaticCertificateJSON(const QUuid& entityID) {
|
||||
QByteArray result;
|
||||
if (_entityTree) {
|
||||
_entityTree->withReadLock([&] {
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
|
||||
if (entity) {
|
||||
result = entity->getProperties().getStaticCertificateJSON();
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::verifyStaticCertificateProperties(const QUuid& entityID) {
|
||||
bool result = false;
|
||||
if (_entityTree) {
|
||||
|
|
|
@ -423,6 +423,12 @@ public slots:
|
|||
*/
|
||||
Q_INVOKABLE glm::mat4 getEntityLocalTransform(const QUuid& entityID);
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* Return the Static Certificate JSON for the specified {EntityID}.
|
||||
* @return {QByteArray} The Static Certificate JSON for the specified entity.
|
||||
*/
|
||||
Q_INVOKABLE QString getStaticCertificateJSON(const QUuid& entityID);
|
||||
Q_INVOKABLE bool verifyStaticCertificateProperties(const QUuid& entityID);
|
||||
|
||||
signals:
|
||||
|
|
|
@ -29,7 +29,6 @@ void EntitySimulation::setEntityTree(EntityTreePointer tree) {
|
|||
}
|
||||
|
||||
void EntitySimulation::updateEntities() {
|
||||
PROFILE_RANGE(simulation_physics, "ES::updateEntities");
|
||||
QMutexLocker lock(&_mutex);
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
|
@ -38,12 +37,7 @@ void EntitySimulation::updateEntities() {
|
|||
callUpdateOnEntitiesThatNeedIt(now);
|
||||
moveSimpleKinematics(now);
|
||||
updateEntitiesInternal(now);
|
||||
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "Sort");
|
||||
PerformanceTimer perfTimer("sortingEntities");
|
||||
sortEntitiesThatMoved();
|
||||
}
|
||||
sortEntitiesThatMoved();
|
||||
}
|
||||
|
||||
void EntitySimulation::takeEntitiesToDelete(VectorOfEntities& entitiesToDelete) {
|
||||
|
@ -101,6 +95,7 @@ void EntitySimulation::changeEntityInternal(EntityItemPointer entity) {
|
|||
// protected
|
||||
void EntitySimulation::expireMortalEntities(const quint64& now) {
|
||||
if (now > _nextExpiry) {
|
||||
PROFILE_RANGE_EX(simulation_physics, "ExpireMortals", 0xffff00ff, (uint64_t)_mortalEntities.size());
|
||||
// only search for expired entities if we expect to find one
|
||||
_nextExpiry = quint64(-1);
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
@ -146,6 +141,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
|
|||
|
||||
// protected
|
||||
void EntitySimulation::sortEntitiesThatMoved() {
|
||||
PROFILE_RANGE_EX(simulation_physics, "SortTree", 0xffff00ff, (uint64_t)_entitiesToSort.size());
|
||||
// NOTE: this is only for entities that have been moved by THIS EntitySimulation.
|
||||
// External changes to entity position/shape are expected to be sorted outside of the EntitySimulation.
|
||||
MovingEntitiesOperator moveOperator;
|
||||
|
@ -265,7 +261,7 @@ void EntitySimulation::clearEntities() {
|
|||
}
|
||||
|
||||
void EntitySimulation::moveSimpleKinematics(const quint64& now) {
|
||||
PROFILE_RANGE_EX(simulation_physics, "Kinematics", 0xffff00ff, (uint64_t)_simpleKinematicEntities.size());
|
||||
PROFILE_RANGE_EX(simulation_physics, "MoveSimples", 0xffff00ff, (uint64_t)_simpleKinematicEntities.size());
|
||||
SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin();
|
||||
while (itemItr != _simpleKinematicEntities.end()) {
|
||||
EntityItemPointer entity = *itemItr;
|
||||
|
|
|
@ -1308,7 +1308,7 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
|
|||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL;
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||
QJsonObject request;
|
||||
request["certificate_id"] = certID;
|
||||
|
@ -1770,24 +1770,26 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) {
|
|||
}
|
||||
|
||||
void EntityTree::update(bool simulate) {
|
||||
PROFILE_RANGE(simulation_physics, "ET::update");
|
||||
PROFILE_RANGE(simulation_physics, "UpdateTree");
|
||||
fixupNeedsParentFixups();
|
||||
if (simulate && _simulation) {
|
||||
withWriteLock([&] {
|
||||
_simulation->updateEntities();
|
||||
VectorOfEntities pendingDeletes;
|
||||
_simulation->takeEntitiesToDelete(pendingDeletes);
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "Deletes");
|
||||
VectorOfEntities pendingDeletes;
|
||||
_simulation->takeEntitiesToDelete(pendingDeletes);
|
||||
if (pendingDeletes.size() > 0) {
|
||||
// translate into list of ID's
|
||||
QSet<EntityItemID> idsToDelete;
|
||||
|
||||
if (pendingDeletes.size() > 0) {
|
||||
// translate into list of ID's
|
||||
QSet<EntityItemID> idsToDelete;
|
||||
for (auto entity : pendingDeletes) {
|
||||
idsToDelete.insert(entity->getEntityItemID());
|
||||
}
|
||||
|
||||
for (auto entity : pendingDeletes) {
|
||||
idsToDelete.insert(entity->getEntityItemID());
|
||||
// delete these things the roundabout way
|
||||
deleteEntities(idsToDelete, true);
|
||||
}
|
||||
|
||||
// delete these things the roundabout way
|
||||
deleteEntities(idsToDelete, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const E
|
|||
|
||||
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID)
|
||||
{
|
||||
_lastAnimated = usecTimestampNow();
|
||||
// set the last animated when interface (re)starts
|
||||
_type = EntityTypes::Model;
|
||||
_lastKnownCurrentFrame = -1;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
|
@ -186,6 +188,105 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
}
|
||||
|
||||
|
||||
|
||||
// added update function back for property fix
|
||||
void ModelEntityItem::update(const quint64& now) {
|
||||
|
||||
{
|
||||
auto currentAnimationProperties = this->getAnimationProperties();
|
||||
|
||||
if (_previousAnimationProperties != currentAnimationProperties) {
|
||||
withWriteLock([&] {
|
||||
// if we hit start animation or change the first or last frame then restart the animation
|
||||
if ((currentAnimationProperties.getFirstFrame() != _previousAnimationProperties.getFirstFrame()) ||
|
||||
(currentAnimationProperties.getLastFrame() != _previousAnimationProperties.getLastFrame()) ||
|
||||
(currentAnimationProperties.getRunning() && !_previousAnimationProperties.getRunning())) {
|
||||
|
||||
// when we start interface and the property is are set then the current frame is initialized to -1
|
||||
if (_currentFrame < 0) {
|
||||
// don't reset _lastAnimated here because we need the timestamp from the ModelEntityItem constructor for when the properties were set
|
||||
_currentFrame = currentAnimationProperties.getCurrentFrame();
|
||||
setAnimationCurrentFrame(_currentFrame);
|
||||
} else {
|
||||
_lastAnimated = usecTimestampNow();
|
||||
_currentFrame = currentAnimationProperties.getFirstFrame();
|
||||
setAnimationCurrentFrame(currentAnimationProperties.getFirstFrame());
|
||||
}
|
||||
} else if (!currentAnimationProperties.getRunning() && _previousAnimationProperties.getRunning()) {
|
||||
_currentFrame = currentAnimationProperties.getFirstFrame();
|
||||
setAnimationCurrentFrame(_currentFrame);
|
||||
} else if (currentAnimationProperties.getCurrentFrame() != _previousAnimationProperties.getCurrentFrame()) {
|
||||
// don't reset _lastAnimated here because the currentFrame was set with the previous setting of _lastAnimated
|
||||
_currentFrame = currentAnimationProperties.getCurrentFrame();
|
||||
}
|
||||
|
||||
});
|
||||
_previousAnimationProperties = this->getAnimationProperties();
|
||||
|
||||
}
|
||||
|
||||
if (isAnimatingSomething()) {
|
||||
if (!(getAnimationFirstFrame() < 0) && !(getAnimationFirstFrame() > getAnimationLastFrame())) {
|
||||
updateFrameCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityItem::update(now);
|
||||
}
|
||||
|
||||
bool ModelEntityItem::needsToCallUpdate() const {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelEntityItem::updateFrameCount() {
|
||||
|
||||
if (_currentFrame < 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_lastAnimated) {
|
||||
_lastAnimated = usecTimestampNow();
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = usecTimestampNow();
|
||||
|
||||
// update the interval since the last animation.
|
||||
auto interval = now - _lastAnimated;
|
||||
_lastAnimated = now;
|
||||
|
||||
// if fps is negative then increment timestamp and return.
|
||||
if (getAnimationFPS() < 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
int updatedFrameCount = getAnimationLastFrame() - getAnimationFirstFrame() + 1;
|
||||
|
||||
if (!getAnimationHold() && getAnimationIsPlaying()) {
|
||||
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
|
||||
_currentFrame += (deltaTime * getAnimationFPS());
|
||||
if (_currentFrame > getAnimationLastFrame()) {
|
||||
if (getAnimationLoop()) {
|
||||
_currentFrame = getAnimationFirstFrame() + (int)(glm::floor(_currentFrame - getAnimationFirstFrame())) % (updatedFrameCount - 1);
|
||||
} else {
|
||||
_currentFrame = getAnimationLastFrame();
|
||||
}
|
||||
} else if (_currentFrame < getAnimationFirstFrame()) {
|
||||
if (getAnimationFirstFrame() < 0) {
|
||||
_currentFrame = 0;
|
||||
} else {
|
||||
_currentFrame = getAnimationFirstFrame();
|
||||
}
|
||||
}
|
||||
// qCDebug(entities) << "in update frame " << _currentFrame;
|
||||
setAnimationCurrentFrame(_currentFrame);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ModelEntityItem::debugDump() const {
|
||||
qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID();
|
||||
qCDebug(entities) << " edited ago:" << getEditedAgo();
|
||||
|
@ -538,6 +639,13 @@ void ModelEntityItem::setAnimationLoop(bool loop) {
|
|||
});
|
||||
}
|
||||
|
||||
bool ModelEntityItem::getAnimationLoop() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _animationProperties.getLoop();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void ModelEntityItem::setAnimationHold(bool hold) {
|
||||
withWriteLock([&] {
|
||||
_animationProperties.setHold(hold);
|
||||
|
@ -573,8 +681,9 @@ float ModelEntityItem::getAnimationLastFrame() const {
|
|||
return _animationProperties.getLastFrame();
|
||||
});
|
||||
}
|
||||
|
||||
bool ModelEntityItem::getAnimationIsPlaying() const {
|
||||
return resultWithReadLock<float>([&] {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _animationProperties.getRunning();
|
||||
});
|
||||
}
|
||||
|
@ -585,8 +694,15 @@ float ModelEntityItem::getAnimationCurrentFrame() const {
|
|||
});
|
||||
}
|
||||
|
||||
bool ModelEntityItem::isAnimatingSomething() const {
|
||||
float ModelEntityItem::getAnimationFPS() const {
|
||||
return resultWithReadLock<float>([&] {
|
||||
return _animationProperties.getFPS();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool ModelEntityItem::isAnimatingSomething() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return !_animationProperties.getURL().isEmpty() &&
|
||||
_animationProperties.getRunning() &&
|
||||
(_animationProperties.getFPS() != 0.0f);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <ThreadSafeValueCache.h>
|
||||
#include "AnimationPropertyGroup.h"
|
||||
|
||||
|
||||
class ModelEntityItem : public EntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -46,8 +47,11 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
//virtual void update(const quint64& now) override;
|
||||
//virtual bool needsToCallUpdate() const override;
|
||||
// update() and needstocallupdate() added back for the entity property fix
|
||||
virtual void update(const quint64& now) override;
|
||||
virtual bool needsToCallUpdate() const override;
|
||||
void updateFrameCount();
|
||||
|
||||
virtual void debugDump() const override;
|
||||
|
||||
void setShapeType(ShapeType type) override;
|
||||
|
@ -90,6 +94,7 @@ public:
|
|||
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
|
||||
|
||||
void setAnimationLoop(bool loop);
|
||||
bool getAnimationLoop() const;
|
||||
|
||||
void setAnimationHold(bool hold);
|
||||
bool getAnimationHold() const;
|
||||
|
@ -102,6 +107,7 @@ public:
|
|||
|
||||
bool getAnimationIsPlaying() const;
|
||||
float getAnimationCurrentFrame() const;
|
||||
float getAnimationFPS() const;
|
||||
bool isAnimatingSomething() const;
|
||||
|
||||
static const QString DEFAULT_TEXTURES;
|
||||
|
@ -147,7 +153,7 @@ protected:
|
|||
};
|
||||
|
||||
QVector<ModelJointData> _localJointData;
|
||||
int _lastKnownCurrentFrame;
|
||||
int _lastKnownCurrentFrame{-1};
|
||||
|
||||
rgbColor _color;
|
||||
QString _modelURL;
|
||||
|
@ -160,6 +166,11 @@ protected:
|
|||
QString _textures;
|
||||
|
||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||
|
||||
private:
|
||||
uint64_t _lastAnimated{ 0 };
|
||||
AnimationPropertyGroup _previousAnimationProperties;
|
||||
float _currentFrame{ -1.0f };
|
||||
};
|
||||
|
||||
#endif // hifi_ModelEntityItem_h
|
||||
|
|
|
@ -56,7 +56,7 @@ float OBJTokenizer::getFloat() {
|
|||
return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data());
|
||||
}
|
||||
|
||||
int OBJTokenizer::nextToken() {
|
||||
int OBJTokenizer::nextToken(bool allowSpaceChar /*= false*/) {
|
||||
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
||||
int token = _pushedBackToken;
|
||||
_pushedBackToken = NO_PUSHBACKED_TOKEN;
|
||||
|
@ -93,7 +93,7 @@ int OBJTokenizer::nextToken() {
|
|||
_datum = "";
|
||||
_datum.append(ch);
|
||||
while (_device->getChar(&ch)) {
|
||||
if (QChar(ch).isSpace() || ch == '\"') {
|
||||
if ((QChar(ch).isSpace() || ch == '\"') && (!allowSpaceChar || ch != ' ')) {
|
||||
ungetChar(ch); // read until we encounter a special character, then replace it
|
||||
break;
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
|||
currentMaterialName = QString("part-") + QString::number(_partCounter++);
|
||||
}
|
||||
} else if (token == "mtllib" && !_url.isEmpty()) {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
if (tokenizer.nextToken(true) != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
}
|
||||
QByteArray libraryName = tokenizer.getDatum();
|
||||
|
|
|
@ -11,7 +11,7 @@ public:
|
|||
DATUM_TOKEN = 0x100,
|
||||
COMMENT_TOKEN = 0x101
|
||||
};
|
||||
int nextToken();
|
||||
int nextToken(bool allowSpaceChar = false);
|
||||
const QByteArray& getDatum() const { return _datum; }
|
||||
bool isNextTokenFloat();
|
||||
const QByteArray getLineAsDatum(); // some "filenames" have spaces in them
|
||||
|
|
|
@ -981,7 +981,7 @@ public:
|
|||
static QImage extractEquirectangularFace(const QImage& source, gpu::Texture::CubeFace face, int faceWidth) {
|
||||
QImage image(faceWidth, faceWidth, source.format());
|
||||
|
||||
glm::vec2 dstInvSize(1.0f / (float)source.width(), 1.0f / (float)source.height());
|
||||
glm::vec2 dstInvSize(1.0f / faceWidth);
|
||||
|
||||
struct CubeToXYZ {
|
||||
gpu::Texture::CubeFace _face;
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
void setTemporaryDomain(const QUuid& domainID, const QString& key);
|
||||
const QString& getTemporaryDomainKey(const QUuid& domainID) { return _accountInfo.getTemporaryDomainKey(domainID); }
|
||||
|
||||
QUrl getMetaverseServerURL() { return NetworkingConstants::METAVERSE_SERVER_URL; }
|
||||
QUrl getMetaverseServerURL() { return NetworkingConstants::METAVERSE_SERVER_URL(); }
|
||||
|
||||
public slots:
|
||||
void requestAccessToken(const QString& login, const QString& password);
|
||||
|
|
|
@ -127,7 +127,11 @@ void Assignment::swap(Assignment& otherAssignment) {
|
|||
}
|
||||
|
||||
const char* Assignment::getTypeName() const {
|
||||
switch (_type) {
|
||||
return typeToString(_type);
|
||||
}
|
||||
|
||||
const char* Assignment::typeToString(Assignment::Type type) {
|
||||
switch (type) {
|
||||
case Assignment::AudioMixerType:
|
||||
return "audio-mixer";
|
||||
case Assignment::AvatarMixerType:
|
||||
|
|
|
@ -28,6 +28,7 @@ class Assignment : public QObject {
|
|||
public:
|
||||
|
||||
enum Type : uint8_t {
|
||||
FirstType = 0,
|
||||
AudioMixerType = 0,
|
||||
AvatarMixerType = 1,
|
||||
AgentType = 2,
|
||||
|
@ -89,6 +90,7 @@ public:
|
|||
const QString& getNodeVersion() const { return _nodeVersion; }
|
||||
|
||||
const char* getTypeName() const;
|
||||
static const char* typeToString(Assignment::Type type);
|
||||
|
||||
friend QDebug operator<<(QDebug debug, const Assignment& assignment);
|
||||
friend QDataStream& operator<<(QDataStream &out, const Assignment& assignment);
|
||||
|
|
|
@ -12,15 +12,31 @@
|
|||
#ifndef hifi_NetworkingConstants_h
|
||||
#define hifi_NetworkingConstants_h
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
namespace NetworkingConstants {
|
||||
// If you want to use STAGING instead of STABLE,
|
||||
// don't forget to ALSO change the Domain Server Metaverse Server URL inside of:
|
||||
// links from the Domain Server web interface (like the connect account token generation)
|
||||
// will still point at stable unless you ALSO change the Domain Server Metaverse Server URL inside of:
|
||||
// <hifi repo>\domain-server\resources\web\js\shared.js
|
||||
|
||||
// You can avoid changing that and still effectively use a connected domain on staging
|
||||
// if you manually generate a personal access token for the domains scope
|
||||
// at https://staging.highfidelity.com/user/tokens/new?for_domain_server=true
|
||||
|
||||
const QUrl METAVERSE_SERVER_URL_STABLE("https://metaverse.highfidelity.com");
|
||||
const QUrl METAVERSE_SERVER_URL_STAGING("https://staging.highfidelity.com");
|
||||
const QUrl METAVERSE_SERVER_URL = METAVERSE_SERVER_URL_STABLE;
|
||||
|
||||
// You can change the return of this function if you want to use a custom metaverse URL at compile time
|
||||
// or you can pass a custom URL via the env variable
|
||||
static const QUrl METAVERSE_SERVER_URL() {
|
||||
static const QString HIFI_METAVERSE_URL_ENV = "HIFI_METAVERSE_URL";
|
||||
static const QUrl serverURL = QProcessEnvironment::systemEnvironment().contains(HIFI_METAVERSE_URL_ENV)
|
||||
? QUrl(QProcessEnvironment::systemEnvironment().value(HIFI_METAVERSE_URL_ENV))
|
||||
: METAVERSE_SERVER_URL_STABLE;
|
||||
return serverURL;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_NetworkingConstants_h
|
||||
|
|
|
@ -35,7 +35,7 @@ QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::O
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (accountManager->hasValidAccessToken()
|
||||
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL.host()) {
|
||||
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL().host()) {
|
||||
QNetworkRequest authenticatedRequest(req);
|
||||
authenticatedRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
|
|
@ -141,3 +141,16 @@ void UserActivityLoggerScriptingInterface::commerceWalletSetupFinished(int times
|
|||
payload["secondsToComplete"] = secondsToComplete;
|
||||
doLogAction("commerceWalletSetupFinished", payload);
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::commercePassphraseEntry(QString source) {
|
||||
QJsonObject payload;
|
||||
payload["source"] = source;
|
||||
doLogAction("commercePassphraseEntry", payload);
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::commercePassphraseAuthenticationStatus(QString status) {
|
||||
QJsonObject payload;
|
||||
payload["status"] = status;
|
||||
doLogAction("commercePassphraseAuthenticationStatus", payload);
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
Q_INVOKABLE void commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain);
|
||||
Q_INVOKABLE void commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName);
|
||||
Q_INVOKABLE void commerceWalletSetupFinished(int timestamp, QString setupAttemptID, int secondsToComplete);
|
||||
Q_INVOKABLE void commercePassphraseEntry(QString source);
|
||||
Q_INVOKABLE void commercePassphraseAuthenticationStatus(QString status);
|
||||
private:
|
||||
void doLogAction(QString action, QJsonObject details = {});
|
||||
};
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "Connection.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -60,6 +62,15 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq
|
|||
_ack2Packet = ControlPacket::create(ControlPacket::ACK2, ACK2_PAYLOAD_BYTES);
|
||||
_lossReport = ControlPacket::create(ControlPacket::NAK, NAK_PACKET_PAYLOAD_BYTES);
|
||||
_handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, HANDSHAKE_ACK_PAYLOAD_BYTES);
|
||||
|
||||
|
||||
// setup psuedo-random number generation shared by all connections
|
||||
static std::random_device rd;
|
||||
static std::mt19937 generator(rd());
|
||||
static std::uniform_int_distribution<> distribution(0, SequenceNumber::MAX);
|
||||
|
||||
// randomize the intial sequence number
|
||||
_initialSequenceNumber = SequenceNumber(distribution(generator));
|
||||
}
|
||||
|
||||
Connection::~Connection() {
|
||||
|
@ -79,11 +90,11 @@ void Connection::stopSendQueue() {
|
|||
// tell the send queue to stop and be deleted
|
||||
|
||||
sendQueue->stop();
|
||||
|
||||
_lastMessageNumber = sendQueue->getCurrentMessageNumber();
|
||||
|
||||
sendQueue->deleteLater();
|
||||
|
||||
// since we're stopping the send queue we should consider our handshake ACK not receieved
|
||||
_hasReceivedHandshakeACK = false;
|
||||
|
||||
// wait on the send queue thread so we know the send queue is gone
|
||||
sendQueueThread->quit();
|
||||
sendQueueThread->wait();
|
||||
|
@ -101,13 +112,19 @@ void Connection::setMaxBandwidth(int maxBandwidth) {
|
|||
|
||||
SendQueue& Connection::getSendQueue() {
|
||||
if (!_sendQueue) {
|
||||
|
||||
// we may have a sequence number from the previous inactive queue - re-use that so that the
|
||||
// receiver is getting the sequence numbers it expects (given that the connection must still be active)
|
||||
|
||||
// Lasily create send queue
|
||||
_sendQueue = SendQueue::create(_parentSocket, _destination);
|
||||
_lastReceivedACK = _sendQueue->getCurrentSequenceNumber();
|
||||
|
||||
if (!_hasReceivedHandshakeACK) {
|
||||
// First time creating a send queue for this connection
|
||||
_sendQueue = SendQueue::create(_parentSocket, _destination, _initialSequenceNumber - 1, _lastMessageNumber, _hasReceivedHandshakeACK);
|
||||
_lastReceivedACK = _sendQueue->getCurrentSequenceNumber();
|
||||
} else {
|
||||
// Connection already has a handshake from a previous send queue
|
||||
_sendQueue = SendQueue::create(_parentSocket, _destination, _lastReceivedACK, _lastMessageNumber, _hasReceivedHandshakeACK);
|
||||
}
|
||||
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Created SendQueue for connection to" << _destination;
|
||||
|
@ -142,14 +159,6 @@ void Connection::queueInactive() {
|
|||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Connection to" << _destination << "has stopped its SendQueue.";
|
||||
#endif
|
||||
|
||||
if (!_hasReceivedHandshake || !_isReceivingData) {
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Connection SendQueue to" << _destination << "stopped and no data is being received - stopping connection.";
|
||||
#endif
|
||||
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::queueTimeout() {
|
||||
|
@ -184,11 +193,16 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr<Packet> packet) {
|
|||
|
||||
while (pendingMessage.hasAvailablePackets()) {
|
||||
auto packet = pendingMessage.removeNextPacket();
|
||||
_parentSocket->messageReceived(std::move(packet));
|
||||
}
|
||||
|
||||
if (pendingMessage.isComplete()) {
|
||||
_pendingReceivedMessages.erase(messageNumber);
|
||||
auto packetPosition = packet->getPacketPosition();
|
||||
|
||||
_parentSocket->messageReceived(std::move(packet));
|
||||
|
||||
// if this was the last or only packet, then we can remove the pending message from our hash
|
||||
if (packetPosition == Packet::PacketPosition::LAST ||
|
||||
packetPosition == Packet::PacketPosition::ONLY) {
|
||||
_pendingReceivedMessages.erase(messageNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,19 +222,6 @@ void Connection::sync() {
|
|||
&& duration_cast<seconds>(sincePacketReceive).count() >= MIN_SECONDS_BEFORE_EXPIRY ) {
|
||||
// the receive side of this connection is expired
|
||||
_isReceivingData = false;
|
||||
|
||||
// if we don't have a send queue that means the whole connection has expired and we can emit our signal
|
||||
// otherwise we'll wait for it to also timeout before cleaning up
|
||||
if (!_sendQueue) {
|
||||
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Connection to" << _destination << "no longer receiving any data and there is currently no send queue - stopping connection.";
|
||||
#endif
|
||||
|
||||
deactivate();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the number of light ACKs or non SYN ACKs during this sync interval
|
||||
|
@ -242,26 +243,6 @@ void Connection::sync() {
|
|||
sendTimeoutNAK();
|
||||
}
|
||||
}
|
||||
} else if (!_sendQueue) {
|
||||
// we haven't received a packet and we're not sending
|
||||
// this most likely means we were started erroneously
|
||||
// check the start time for this connection and auto expire it after 5 seconds of not receiving or sending any data
|
||||
static const int CONNECTION_NOT_USED_EXPIRY_SECONDS = 5;
|
||||
auto secondsSinceStart = duration_cast<seconds>(p_high_resolution_clock::now() - _connectionStart).count();
|
||||
|
||||
if (secondsSinceStart >= CONNECTION_NOT_USED_EXPIRY_SECONDS) {
|
||||
// it's been CONNECTION_NOT_USED_EXPIRY_SECONDS and nothing has actually happened with this connection
|
||||
// consider it inactive and emit our inactivity signal
|
||||
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Connection to" << _destination << "did not receive or send any data in last"
|
||||
<< CONNECTION_NOT_USED_EXPIRY_SECONDS << "seconds - stopping connection.";
|
||||
#endif
|
||||
|
||||
deactivate();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -444,7 +425,6 @@ void Connection::sendHandshakeRequest() {
|
|||
}
|
||||
|
||||
bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, int packetSize, int payloadSize) {
|
||||
|
||||
if (!_hasReceivedHandshake) {
|
||||
// Refuse to process any packets until we've received the handshake
|
||||
// Send handshake request to re-request a handshake
|
||||
|
@ -536,7 +516,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in
|
|||
} else {
|
||||
_stats.recordReceivedPackets(payloadSize, packetSize);
|
||||
}
|
||||
|
||||
|
||||
return !wasDuplicate;
|
||||
}
|
||||
|
||||
|
@ -827,11 +807,13 @@ void Connection::processHandshakeACK(ControlPacketPointer controlPacket) {
|
|||
SequenceNumber initialSequenceNumber;
|
||||
controlPacket->readPrimitive(&initialSequenceNumber);
|
||||
|
||||
// hand off this handshake ACK to the send queue so it knows it can start sending
|
||||
getSendQueue().handshakeACK(initialSequenceNumber);
|
||||
|
||||
// indicate that handshake ACK was received
|
||||
_hasReceivedHandshakeACK = true;
|
||||
if (initialSequenceNumber == _initialSequenceNumber) {
|
||||
// hand off this handshake ACK to the send queue so it knows it can start sending
|
||||
getSendQueue().handshakeACK();
|
||||
|
||||
// indicate that handshake ACK was received
|
||||
_hasReceivedHandshakeACK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ class Socket;
|
|||
class PendingReceivedMessage {
|
||||
public:
|
||||
void enqueuePacket(std::unique_ptr<Packet> packet);
|
||||
bool isComplete() const { return _hasLastPacket && _numPackets == _packets.size(); }
|
||||
bool hasAvailablePackets() const;
|
||||
std::unique_ptr<Packet> removeNextPacket();
|
||||
|
||||
|
@ -72,8 +71,6 @@ public:
|
|||
void queueReceivedMessagePacket(std::unique_ptr<Packet> packet);
|
||||
|
||||
ConnectionStats::Stats sampleStats() { return _stats.sample(); }
|
||||
|
||||
bool isActive() const { return _isActive; }
|
||||
|
||||
HifiSockAddr getDestination() const { return _destination; }
|
||||
|
||||
|
@ -83,7 +80,6 @@ public:
|
|||
|
||||
signals:
|
||||
void packetSent();
|
||||
void connectionInactive(const HifiSockAddr& sockAddr);
|
||||
void receiverHandshakeRequestComplete(const HifiSockAddr& sockAddr);
|
||||
|
||||
private slots:
|
||||
|
@ -112,8 +108,6 @@ private:
|
|||
void resetReceiveState();
|
||||
void resetRTT();
|
||||
|
||||
void deactivate() { _isActive = false; emit connectionInactive(_destination); }
|
||||
|
||||
SendQueue& getSendQueue();
|
||||
SequenceNumber nextACK() const;
|
||||
void updateRTT(int rtt);
|
||||
|
@ -138,9 +132,11 @@ private:
|
|||
p_high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender
|
||||
|
||||
bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection
|
||||
bool _isActive { true }; // flag used for inactivity of connection
|
||||
|
||||
SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer SendQueue on creation, identifies connection during re-connect requests
|
||||
SequenceNumber _initialSequenceNumber; // Randomized on Connection creation, identifies connection during re-connect requests
|
||||
SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer Connection on creation, identifies connection during re-connect requests
|
||||
|
||||
MessageNumber _lastMessageNumber { 0 };
|
||||
|
||||
LossList _lossList; // List of all missing packets
|
||||
SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer
|
||||
|
|
|
@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
case PacketType::EntityPhysics:
|
||||
return static_cast<PacketVersion>(EntityVersion::HazeEffect);
|
||||
return static_cast<PacketVersion>(EntityVersion::StaticCertJsonVersionOne);
|
||||
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConnectionIdentifier);
|
||||
|
|
|
@ -199,7 +199,8 @@ QDebug operator<<(QDebug debug, const PacketType& type);
|
|||
enum class EntityVersion : PacketVersion {
|
||||
StrokeColorProperty = 77,
|
||||
HasDynamicOwnershipTests,
|
||||
HazeEffect
|
||||
HazeEffect,
|
||||
StaticCertJsonVersionOne
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
using namespace udt;
|
||||
|
||||
PacketQueue::PacketQueue() {
|
||||
PacketQueue::PacketQueue(MessageNumber messageNumber) : _currentMessageNumber(messageNumber) {
|
||||
_channels.emplace_back(new std::list<PacketPointer>());
|
||||
}
|
||||
|
||||
|
|