//// 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. Load more
// // 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' value static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2; #if !defined(Q_OS_ANDROID) static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; #else static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4; #endif #if defined(Q_OS_ANDROID) static bool DISABLE_WATCHDOG = true; #else static const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" }; static bool DISABLE_WATCHDOG = nsightActive() || QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG); #endif static 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;