2204 lines · 107.2 KB · C++
RawDownload
////  Application_Setup.cpp//  interface/src////  Split from Application.cpp by HifiExperiments on 3/30/24//  Created by Andrzej Kapolka on 5/10/13.//  Copyright 2013 High Fidelity, Inc.//  Copyright 2020 Vircadia contributors.//  Copyright 2022-2025 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//  SPDX-License-Identifier: Apache-2.0// #include "Application.h" #include <functional> #include <QDesktopServices>#include <QFontDatabase>#include <QtCore/QCommandLineParser>#include <QtCore/QResource>#include <QtQml/QQmlContext>#include <QtQuick/QQuickWindow> #include <AccountManager.h>#include <AddressManager.h>#include <AnimationCacheScriptingInterface.h>#include <AvatarBookmarks.h>#include <avatar/AvatarPackager.h>#include <avatar/GrabManager.h>#include <audio/AudioScope.h>#include <AudioScriptingInterface.h>#include <AutoUpdater.h>#include <avatar/AvatarManager.h>#include <BuildInfo.h>#include <CameraRootTransformNode.h>#include <crash-handler/CrashHandler.h>#include <DebugDraw.h>#include <DeferredLightingEffect.h>#include <DesktopPreviewProvider.h>#include <display-plugins/CompositorHelper.h>#include <display-plugins/DisplayPlugin.h>#include <DomainAccountManager.h>#include <EntityScriptClient.h>#include <EntityScriptServerLogClient.h>#include <FingerprintUtils.h>#include <FramebufferCache.h>#include <gl/GLHelpers.h>#include <GPUIdent.h>#include <graphics-scripting/GraphicsScriptingInterface.h>#include <hfm/ModelFormatRegistry.h>#include <input-plugins/KeyboardMouseDevice.h>#include <input-plugins/TouchscreenDevice.h>#include <input-plugins/TouchscreenVirtualPadDevice.h>#include <networking/CloseEventSender.h>#include <MainWindow.h>#include <material-networking/TextureCacheScriptingInterface.h>#include <MessagesClient.h>#include <Midi.h>#include <model-networking/ModelCacheScriptingInterface.h>#include <OffscreenUi.h>#include <PickManager.h>#include <plugins/InputConfiguration.h>#include <plugins/OculusPlatformPlugin.h>#include <plugins/PluginManager.h>#include <plugins/SteamClientPlugin.h>#include <PointerManager.h>#include <Preferences.h>#include <procedural/MaterialCacheScriptingInterface.h>#include <procedural/ReferenceMaterial.h>#include <raypick/MouseTransformNode.h>#include <raypick/PickScriptingInterface.h>#include <raypick/PointerScriptingInterface.h>#include <raypick/RayPick.h>#include <raypick/RayPickScriptingInterface.h>#include <recording/ClipCache.h>#include <recording/Deck.h>#include <recording/Frame.h>#include <recording/Recorder.h>#include <recording/RecordingScriptingInterface.h>#include <RenderableEntityItem.h>#include <RenderableTextEntityItem.h>#include <RenderableWebEntityItem.h>#include <ResourceScriptingInterface.h>#include <SceneScriptingInterface.h>#include <ScriptEngines.h>#include <ScriptEntityItem.h>#include <scripting/Audio.h>#include <scripting/AssetMappingsScriptingInterface.h>#include <scripting/ControllerScriptingInterface.h>#include <scripting/DesktopScriptingInterface.h>#include <scripting/HMDScriptingInterface.h>#include <scripting/KeyboardScriptingInterface.h>#include <scripting/SelectionScriptingInterface.h>#include <scripting/TestScriptingInterface.h>#include <scripting/TTSScriptingInterface.h>#include <scripting/WindowScriptingInterface.h>#include <scripting/OSCScriptingInterface.h>#include <ShapeEntityItem.h>#ifndef Q_OS_ANDROID#include <shared/FileLogger.h>#endif#include <shared/GlobalAppProperties.h>#include <shared/PlatformHelper.h>#include <SoundCacheScriptingInterface.h>#include <StatTracker.h>#include <StencilMaskPass.h>#include <ThreadHelpers.h>#include <ui/DialogsManager.h>#include <ui/DomainConnectionModel.h>#include <ui/Keyboard.h>#include <ui/LoginDialog.h>#include <ui/OctreeStatsProvider.h>#include <ui/OffscreenQmlSurfaceCache.h>#include <ui/Snapshot.h>#include <ui/StandAloneJSConsole.h>#include <ui/TabletScriptingInterface.h>#include <ui/ToolbarScriptingInterface.h>#include <UserActivityLogger.h>#include <UserActivityLoggerScriptingInterface.h>#include <UsersScriptingInterface.h>#include <VirtualPadManager.h> #include "ApplicationEventHandler.h"#include "ApplicationMeshProvider.h"#include "AudioClient.h"#include "CrashRecoveryHandler.h"#include "DeadlockWatchdog.h"#include "DiscordRichPresence.h"#include "DiscoverabilityManager.h"#include "FileDialogHelper.h"#include "GLCanvas.h"#include "InterfaceDynamicFactory.h"#include "InterfaceLogging.h"#include "InterfaceParentFinder.h"#include "LocationBookmarks.h"#include "LODManager.h"#include "Menu.h"#include "ResourceRequestObserver.h"#ifndef USE_GL#include "vk/VKWindow.h"#endif#if defined(Q_OS_MAC) || defined(Q_OS_WIN)#include "SpeechRecognizer.h"#endif#include "Util.h" #if defined(Q_OS_WIN)#include <VersionHelpers.h>#endif #if defined(Q_OS_ANDROID)#include "AndroidHelper.h"#endif using namespace std; /*@jsdoc * <p>The <code>Controller.Hardware.Application</code> object has properties representing Interface's state. The property * values are integer IDs, uniquely identifying each output. <em>Read-only.</em></p> * <p>These states can be mapped to actions or functions or <code>Controller.Standard</code> items in a {@link RouteObject} * mapping (e.g., using the {@link RouteObject#when} method). Each data value is either <code>1.0</code> for "true" or * <code>0.0</code> for "false".</p> * <table> *   <thead> *     <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr> *   </thead> *   <tbody> *     <tr><td><code>CameraFirstPerson</code></td><td>number</td><td>number</td><td>The camera is in first-person mode. *       <em>Legacy first person camera mode.</em></td></tr> *     <tr><td><code>CameraFirstPersonLookAt</code></td><td>number</td><td>number</td><td>The camera is in first-person mode. *       <em>Default first person camera mode.</em></td></tr> *     <tr><td><code>CameraThirdPerson</code></td><td>number</td><td>number</td><td>The camera is in third-person mode. *       <em>Legacy third person camera mode.</em></td></tr> *     <tr><td><code>CameraLookAt</code></td><td>number</td><td>number</td><td>The camera is in third-person mode. *       <em>Default third person camera mode.</em></td></tr> *     <tr><td><code>CameraFSM</code></td><td>number</td><td>number</td><td>The camera is in full screen mirror mode. *       <em>Legacy "look at myself" behavior.</em></td></tr> *     <tr><td><code>CameraSelfie</code></td><td>number</td><td>number</td><td>The camera is in selfie mode. *       <em>Default "look at myself" camera mode.</em></td></tr> *     <tr><td><code>CameraIndependent</code></td><td>number</td><td>number</td><td>The camera is in independent mode.</td></tr> *     <tr><td><code>CameraEntity</code></td><td>number</td><td>number</td><td>The camera is in entity mode.</td></tr> *     <tr><td><code>InHMD</code></td><td>number</td><td>number</td><td>The user is in HMD mode.</td></tr> *     <tr><td><code>CaptureMouse</code></td><td>number</td><td>number</td><td>The mouse is captured.  In this mode, *       the mouse is invisible and cannot leave the bounds of Interface, as long as Interface is the active window and *       no menu item is selected.</td></tr> *     <tr><td><code>AdvancedMovement</code></td><td>number</td><td>number</td><td>Advanced movement (walking) controls are *       enabled.</td></tr> *     <tr><td><code>StrafeEnabled</code></td><td>number</td><td>number</td><td>Strafing is enabled</td></tr> *     <tr><td><code>LeftHandDominant</code></td><td>number</td><td>number</td><td>Dominant hand set to left.</td></tr> *     <tr><td><code>RightHandDominant</code></td><td>number</td><td>number</td><td>Dominant hand set to right.</td></tr> *     <tr><td><code>SnapTurn</code></td><td>number</td><td>number</td><td>Snap turn is enabled.</td></tr> *     <tr><td><code>Grounded</code></td><td>number</td><td>number</td><td>The user's avatar is on the ground.</td></tr> *     <tr><td><code>NavigationFocused</code></td><td>number</td><td>number</td><td><em>Not used.</em></td></tr> *     <tr><td><code>PlatformWindows</code></td><td>number</td><td>number</td><td>The operating system is Windows.</td></tr> *     <tr><td><code>PlatformMac</code></td><td>number</td><td>number</td><td>The operating system is Mac.</td></tr> *     <tr><td><code>PlatformAndroid</code></td><td>number</td><td>number</td><td>The operating system is Android.</td></tr> *   </tbody> * </table> * @typedef {object} Controller.Hardware-Application */ static const QString STATE_IN_HMD = "InHMD";static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM";static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";static const QString STATE_CAMERA_FIRST_PERSON_LOOK_AT = "CameraFirstPersonLookat";static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson";static const QString STATE_CAMERA_ENTITY = "CameraEntity";static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent";static const QString STATE_CAMERA_LOOK_AT = "CameraLookAt";static const QString STATE_CAMERA_SELFIE = "CameraSelfie";static const QString STATE_SNAP_TURN = "SnapTurn";static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement";static const QString STATE_GROUNDED = "Grounded";static const QString STATE_NAV_FOCUSED = "NavigationFocused";static const QString STATE_PLATFORM_WINDOWS = "PlatformWindows";static const QString STATE_PLATFORM_MAC = "PlatformMac";static const QString STATE_PLATFORM_ANDROID = "PlatformAndroid";static const QString STATE_LEFT_HAND_DOMINANT = "LeftHandDominant";static const QString STATE_RIGHT_HAND_DOMINANT = "RightHandDominant";static const QString STATE_STRAFE_ENABLED = "StrafeEnabled";static const QString STATE_CAPTURE_MOUSE = "CaptureMouse"; static const QUrl AVATAR_INPUTS_BAR_QML = PathUtils::qmlUrl("AvatarInputsBar.qml");static const QUrl BUBBLE_ICON_QML = PathUtils::qmlUrl("BubbleIcon.qml"); static const int ENTITY_SERVER_ADDED_TIMEOUT = 5000; // For processing on QThreadPool, we target a number of threads after reserving some// based on how many are being consumed by the application and the display plugin.  However,// we will never drop below the 'min' valuestatic const int MIN_PROCESSING_THREAD_POOL_SIZE = 2; #if !defined(Q_OS_ANDROID)static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;#elsestatic const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;#endif #if defined(Q_OS_ANDROID)static bool DISABLE_WATCHDOG = true;#elsestatic const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" };static bool DISABLE_WATCHDOG = nsightActive() || QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG);#endifstatic const int WATCHDOG_TIMER_TIMEOUT = 100; #if defined(Q_OS_ANDROID)static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt";#endif bool setupEssentials(const QCommandLineParser& parser, bool runningMarkerExisted) {    const int listenPort = parser.isSet("listenPort") ? parser.value("listenPort").toInt() : INVALID_PORT;     bool suppressPrompt = parser.isSet("suppress-settings-reset");     // set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store    qApp->setProperty(hifi::properties::OCULUS_STORE, parser.isSet("oculus-store"));     // emulate standalone device    qApp->setProperty(hifi::properties::STANDALONE, parser.isSet("standalone"));     // Ignore any previous crashes if running from command line with a test script.    bool inTestMode = parser.isSet("testScript");     bool previousSessionCrashed { false };    if (!inTestMode) {        // TODO: FIX        previousSessionCrashed = CrashRecoveryHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);    }     // get dir to use for cache    if (parser.isSet("cache")) {        qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, parser.value("cache"));    }     {        const QString resourcesBinaryFile = PathUtils::getRccPath();        qCInfo(interfaceapp) << "Loading primary resources from" << resourcesBinaryFile;         if (!QFile::exists(resourcesBinaryFile)) {            throw std::runtime_error(QString("Unable to find primary resources from '%1'").arg(resourcesBinaryFile).toStdString());        }        if (!QResource::registerResource(resourcesBinaryFile)) {            throw std::runtime_error(QString("Unable to load primary resources from '%1'").arg(resourcesBinaryFile).toStdString());        }    }     DependencyManager::set<ScriptInitializers>();     // Tell the plugin manager about our statically linked plugins    auto pluginManager = PluginManager::getInstance();    if (auto steamClient = pluginManager->getSteamClientPlugin()) {        steamClient->init();    }    if (auto oculusPlatform = pluginManager->getOculusPlatformPlugin()) {        oculusPlatform->init();    }     PROFILE_SET_THREAD_NAME("Main Thread");     QString defaultScriptsOverrideOption = parser.value("defaultScriptsOverride");     DependencyManager::registerInheritance<LimitedNodeList, NodeList>();    DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();    DependencyManager::registerInheritance<EntityDynamicFactoryInterface, InterfaceDynamicFactory>();    DependencyManager::registerInheritance<SpatialParentFinder, InterfaceParentFinder>();     // Set dependencies    DependencyManager::set<PickManager>();    DependencyManager::set<PointerManager>();    DependencyManager::set<RayPickScriptingInterface>();    DependencyManager::set<PointerScriptingInterface>();    DependencyManager::set<PickScriptingInterface>();    DependencyManager::set<Cursor::Manager>();    DependencyManager::set<VirtualPad::Manager>();    DependencyManager::set<DesktopPreviewProvider>();#if defined(Q_OS_ANDROID)    DependencyManager::set<AccountManager>(true); // use the default user agent getter#else    DependencyManager::set<AccountManager>(true, std::bind(&Application::getUserAgent, qApp));#endif    DependencyManager::set<DomainAccountManager>();    DependencyManager::set<StatTracker>();    DependencyManager::set<ScriptEngines>(ScriptManager::CLIENT_SCRIPT, defaultScriptsOverrideOption);    DependencyManager::set<Preferences>();    DependencyManager::set<recording::Deck>();    DependencyManager::set<recording::Recorder>();    DependencyManager::set<AddressManager>();    DependencyManager::set<NodeList>(NodeType::Agent, listenPort);    DependencyManager::set<recording::ClipCache>();    DependencyManager::set<GeometryCache>();    DependencyManager::set<ModelFormatRegistry>(); // ModelFormatRegistry must be defined before ModelCache. See the ModelCache constructor.    DependencyManager::set<ModelCache>();    DependencyManager::set<ModelCacheScriptingInterface>();    DependencyManager::set<ScriptCache>();    DependencyManager::set<SoundCache>();    DependencyManager::set<SoundCacheScriptingInterface>();    DependencyManager::set<AudioClient>();    DependencyManager::set<AudioScope>();    DependencyManager::set<DeferredLightingEffect>();    DependencyManager::set<TextureCache>();    DependencyManager::set<MaterialCache>();    DependencyManager::set<TextureCacheScriptingInterface>();    DependencyManager::set<MaterialCacheScriptingInterface>();    DependencyManager::set<FramebufferCache>();    DependencyManager::set<AnimationCache>();    DependencyManager::set<AnimationCacheScriptingInterface>();    DependencyManager::set<ModelBlender>();    DependencyManager::set<UsersScriptingInterface>();    DependencyManager::set<AvatarManager>();    DependencyManager::set<LODManager>();    DependencyManager::set<StandAloneJSConsole>();    DependencyManager::set<DialogsManager>();    DependencyManager::set<ResourceCacheSharedItems>();    DependencyManager::set<DesktopScriptingInterface>();    DependencyManager::set<EntityScriptingInterface>(true);    DependencyManager::set<GraphicsScriptingInterface>();    DependencyManager::set<OSCScriptingInterface>();    DependencyManager::registerInheritance<scriptable::ModelProviderFactory, ApplicationMeshProvider>();    DependencyManager::set<ApplicationMeshProvider>();    DependencyManager::set<RecordingScriptingInterface>();    DependencyManager::set<WindowScriptingInterface>();    DependencyManager::set<HMDScriptingInterface>();    DependencyManager::set<ResourceScriptingInterface>();    DependencyManager::set<TabletScriptingInterface>();    DependencyManager::set<InputConfiguration>();    DependencyManager::set<ToolbarScriptingInterface>();    DependencyManager::set<UserActivityLoggerScriptingInterface>();    DependencyManager::set<AssetMappingsScriptingInterface>();    DependencyManager::set<DomainConnectionModel>(); #if defined(Q_OS_MAC) || defined(Q_OS_WIN)    DependencyManager::set<SpeechRecognizer>();#endif    DependencyManager::set<DiscoverabilityManager>();    DependencyManager::set<SceneScriptingInterface>();#if !defined(DISABLE_QML)    DependencyManager::set<OffscreenUi>();    {        auto window = DependencyManager::get<OffscreenUi>()->getWindow();        auto desktopScriptingInterface = DependencyManager::get<DesktopScriptingInterface>();        QObject::connect(window, &QQuickWindow::focusObjectChanged, [desktopScriptingInterface](QObject *object) {            if (object) {                if (object->objectName() == QString("desktop")) {                    emit desktopScriptingInterface->uiFocusChanged(false);                    return;                }                // Signal with empty object name happens in addition to regular named ones and is not necessary here                if (!object->objectName().isEmpty()) {                    emit desktopScriptingInterface->uiFocusChanged(true);                }            }        });    }#endif    DependencyManager::set<Midi>();    DependencyManager::set<PathUtils>();    DependencyManager::set<InterfaceDynamicFactory>();    DependencyManager::set<AudioInjectorManager>();    DependencyManager::set<MessagesClient>();    controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR,                    STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_FIRST_PERSON_LOOK_AT, STATE_CAMERA_THIRD_PERSON,                    STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_LOOK_AT, STATE_CAMERA_SELFIE, STATE_CAPTURE_MOUSE,                    STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED,                    STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } });    DependencyManager::set<UserInputMapper>();    DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();    DependencyManager::set<InterfaceParentFinder>();    DependencyManager::set<EntityTreeRenderer>(true, qApp, qApp);    DependencyManager::set<CompositorHelper>();    DependencyManager::set<OffscreenQmlSurfaceCache>();    DependencyManager::set<EntityScriptClient>();     DependencyManager::set<EntityScriptServerLogClient>();     DependencyManager::set<OctreeStatsProvider>(nullptr);    DependencyManager::set<AvatarBookmarks>();    DependencyManager::set<LocationBookmarks>();    DependencyManager::set<Snapshot>();    DependencyManager::set<CloseEventSender>();    DependencyManager::set<ResourceManager>();    DependencyManager::set<SelectionScriptingInterface>();    DependencyManager::set<TTSScriptingInterface>();     DependencyManager::set<ResourceRequestObserver>();    DependencyManager::set<Keyboard>();    DependencyManager::set<KeyboardScriptingInterface>();    DependencyManager::set<GrabManager>();    DependencyManager::set<AvatarPackager>();    PlatformHelper::setup();     QObject::connect(PlatformHelper::instance(), &PlatformHelper::systemWillWake, [] {        QMetaObject::invokeMethod(DependencyManager::get<NodeList>().data(), "noteAwakening", Qt::QueuedConnection);        QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "noteAwakening", Qt::QueuedConnection);    });     QString setBookmarkValue = parser.value("setBookmark");    if (!setBookmarkValue.isEmpty()) {        // Bookmarks are expected to be in a name=url form.        // An `=` character in the name or url is unsupported.        auto parts = setBookmarkValue.split("=");        if (parts.length() != 2) {            qWarning() << "Malformed setBookmark argument: " << setBookmarkValue;        } else {            qDebug() << "Setting bookmark" << parts[0] << "to" << parts[1];            DependencyManager::get<LocationBookmarks>()->insert(parts[0], parts[1]);        }    }     return previousSessionCrashed;} void Application::initialize(const QCommandLineParser &parser) {    //qCDebug(interfaceapp) << "Setting up essentials";    setupEssentials(parser, _previousSessionCrashed);    qCDebug(interfaceapp) << "Initializing application";     _entitySimulation = std::make_shared<PhysicalEntitySimulation>();    _physicsEngine = std::make_shared<PhysicsEngine>(Vectors::ZERO);    _entityClipboard = std::make_shared<EntityTree>();    _octreeProcessor = std::make_shared<OctreePacketProcessor>();    _entityEditSender = std::make_shared<EntityEditPacketSender>();    _graphicsEngine = std::make_shared<GraphicsEngine>();    _applicationOverlay = std::make_shared<ApplicationOverlay>();    _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();     auto steamClient = PluginManager::getInstance()->getSteamClientPlugin();    setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));     constexpr auto INSTALLER_INI_NAME = "installer.ini";    auto iniPath = QDir(applicationDirPath()).filePath(INSTALLER_INI_NAME);    QFile installerFile { iniPath };    std::unordered_map<QString, QString> installerKeyValues;    if (installerFile.open(QIODevice::ReadOnly)) {        while (!installerFile.atEnd()) {            auto line = installerFile.readLine();            if (!line.isEmpty()) {                auto index = line.indexOf("=");                if (index >= 0) {                    installerKeyValues[line.mid(0, index).trimmed()] = line.mid(index + 1).trimmed();                }            }        }    }     // In practice we shouldn't run across installs that don't have a known installer type.    // Client or Client+Server installs should always have the installer.ini next to their    // respective interface.exe, and Steam installs will be detected as such. If a user were    // to delete the installer.ini, though, and as an example, we won't know the context of the    // original install.    constexpr auto INSTALLER_KEY_TYPE = "type";    constexpr auto INSTALLER_KEY_CAMPAIGN = "campaign";    constexpr auto INSTALLER_TYPE_UNKNOWN = "unknown";    constexpr auto INSTALLER_TYPE_STEAM = "steam";     auto typeIt = installerKeyValues.find(INSTALLER_KEY_TYPE);    QString installerType = INSTALLER_TYPE_UNKNOWN;

Lines 1–500 of 2204.