summaryrefslogtreecommitdiff
path: root/indra/newview/llappviewer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llappviewer.cpp')
-rw-r--r--indra/newview/llappviewer.cpp273
1 files changed, 261 insertions, 12 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 441f43163d..26542a29c6 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -46,6 +46,7 @@
#include "llagentwearables.h"
#include "lldirpicker.h"
#include "llfloaterimcontainer.h"
+#include "llfloaterpreference.h"
#include "llimprocessing.h"
#include "llwindow.h"
#include "llviewerstats.h"
@@ -55,13 +56,16 @@
#include "llmarketplacenotifications.h"
#include "llmd5.h"
#include "llmeshrepository.h"
+#include "llpanelpreferencegamecontrol.h"
#include "llpumpio.h"
#include "llmimetypes.h"
#include "llslurl.h"
#include "llstartup.h"
+#include "llviewermcp.h"
#include "llfocusmgr.h"
#include "llurlfloaterdispatchhandler.h"
#include "llviewerjoystick.h"
+#include "llgamecontrol.h"
#include "llcalc.h"
#include "llconversationlog.h"
#if LL_WINDOWS
@@ -138,10 +142,14 @@
#include "stringize.h"
#include "llcoros.h"
#include "llexception.h"
+#if defined(LL_CEF)
#include "cef/dullahan_version.h"
+#endif
+#if defined(LL_VLC)
#include "vlc/libvlc_version.h"
+#endif
-#if LL_DARWIN
+#if LL_DARWIN && !LL_SDL_WINDOW
#include "llwindowmacosx.h"
#endif
@@ -194,6 +202,7 @@
#include "lldebugview.h"
#include "llconsole.h"
#include "llcontainerview.h"
+#include "lltoolfocus.h"
#include "lltooltip.h"
#include "llsdutil.h"
@@ -220,6 +229,7 @@
#include "llvosurfacepatch.h"
#include "llviewerfloaterreg.h"
#include "llcommandlineparser.h"
+#include "llfloaterpreference.h"
#include "llfloatermemleak.h"
#include "llfloaterreg.h"
#include "llfloatersimplesnapshot.h"
@@ -259,6 +269,11 @@ using namespace LL;
#include "llcoproceduremanager.h"
#include "llviewereventrecorder.h"
+#include <chrono>
+#include "rlvactions.h"
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+
// *FIX: These extern globals should be cleaned up.
// The globals either represent state/config/resource-storage of either
// this app, or another 'component' of the viewer. App globals should be
@@ -274,6 +289,12 @@ using namespace LL;
#include "llappviewerlistener.h"
#ifdef LL_DISCORD
+#ifdef None
+#undef None
+#endif
+#ifdef BadRequest
+#undef BadRequest
+#endif
#define DISCORDPP_IMPLEMENTATION
#include <discordpp.h>
static std::shared_ptr<discordpp::Client> gDiscordClient;
@@ -292,6 +313,7 @@ static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
#if LL_DARWIN
extern void init_apple_menu(const char* product);
+extern bool gHDRDisplaySupport;
#endif // LL_DARWIN
extern bool gRandomizeFramerate;
@@ -328,6 +350,8 @@ LLUUID gLastAgentSessionId;
# define LL_PLATFORM_KEY "mac"
#elif LL_LINUX
# define LL_PLATFORM_KEY "lnx"
+#elif __FreeBSD__
+# define LL_PLATFORM_KEY "bsd"
#else
# error "Unknown Platform"
#endif
@@ -584,8 +608,13 @@ static void settings_to_globals()
LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale"));
#if LL_DARWIN
+#if LL_SDL_WINDOW
+ LLWindowSDL::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL");
+#else
LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL");
#endif
+ gHDRDisplaySupport = gSavedSettings.getBOOL("MPHDRDisplay");
+#endif
#if LL_DARWIN || LL_SDL_WINDOW
gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI");
@@ -600,6 +629,8 @@ static void settings_modify()
LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor");
LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
gDebugGL = gDebugGLSession || gDebugSession;
+ bool noGLDebug = gSavedSettings.getBOOL("MPNoGLDebug");
+ if(noGLDebug) gDebugGL = false;
gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
}
@@ -691,7 +722,7 @@ LLAppViewer::LLAppViewer()
// Need to do this initialization before we do anything else, since anything
// that touches files should really go through the lldir API
- gDirUtilp->initAppDirs("SecondLife");
+ gDirUtilp->initAppDirs("Megapahit");
//
// IMPORTANT! Do NOT put anything that will write
// into the log files during normal startup until AFTER
@@ -933,7 +964,7 @@ bool LLAppViewer::init()
std::string mime_types_name;
#if LL_DARWIN
mime_types_name = "mime_types_mac.xml";
-#elif LL_LINUX
+#elif LL_LINUX || __FreeBSD__
mime_types_name = "mime_types_linux.xml";
#else
mime_types_name = "mime_types.xml";
@@ -1138,6 +1169,31 @@ bool LLAppViewer::init()
LLViewerJoystick::getInstance()->init(false);
}
+ LLGameControl::init(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "gamecontrollerdb.txt"),
+ [](const std::vector<std::string>& keys) -> LLSD
+ {
+ LLSD result = LLSD::emptyMap();
+ for (const std::string& key : keys)
+ {
+ if (gSavedSettings.controlExists(key))
+ {
+ result[key] = gSavedSettings.getLLSD(key);
+ }
+ }
+ return result;
+ },
+ [](const LLSD& key_values)
+ {
+ for (auto it = key_values.beginMap(); it != key_values.endMap(); ++it)
+ {
+ if (gSavedSettings.controlExists(it->first))
+ {
+ gSavedSettings.setLLSD(it->first, it->second);
+ }
+ }
+ },
+ []() { LLPanelPreferenceGameControl::updateDeviceList(); });
+
try
{
initializeSecHandler();
@@ -1149,7 +1205,7 @@ bool LLAppViewer::init()
gGLActive = false;
-#if !LL_LINUX
+#if 0
// Launch VVM update check (Linux updater is future work: Velopack port)
if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive)
{
@@ -1247,6 +1303,7 @@ bool LLAppViewer::init()
LLWorld::createInstance();
LLViewerStatsRecorder::createInstance();
LLSelectMgr::createInstance();
+ LLToolCamera::createInstance();
LLViewerCamera::createInstance();
LL::GLTFSceneManager::createInstance();
@@ -1334,9 +1391,85 @@ bool LLAppViewer::frame()
return ret;
}
+void sendGameControlData()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ const LLGameControl::ServerState& state = LLGameControl::getServerState();
+
+ msg->newMessageFast(_PREHASH_GameControlData);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
+ msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
+ msg->addU8Fast(_PREHASH_Packet, LLGameControl::getNextPacketNum());
+ msg->addU8Fast(_PREHASH_ActionMode, state.mActionMode);
+
+ // Non-modal canonical axes/buttons: pack every available value every message,
+ // whether or not it changed since the last one (no per-field diffing). Trailing
+ // zero axes are truncated and the Buttons block is skipped entirely when zero --
+ // the server assumes anything not packed is zero -- to save bytes.
+ size_t num_axes = state.mAxes.size();
+ while (num_axes > 0 && state.mAxes[num_axes - 1] == 0)
+ {
+ --num_axes;
+ }
+ for (size_t i = 0; i < num_axes; ++i)
+ {
+ msg->nextBlockFast(_PREHASH_Axes);
+ msg->addS16Fast(_PREHASH_Value, state.mAxes[i]);
+ }
+ if (state.mButtons != 0)
+ {
+ msg->nextBlockFast(_PREHASH_Buttons);
+ msg->addU32Fast(_PREHASH_Flags, state.mButtons);
+ }
+
+ // Modal semantic axes/buttons: same truncation policy, except the number of
+ // axes considered depends on ActionMode -- see message_template.msg's
+ // GameControlData doc and LLGameControl::numSemanticAxesForMode() -- since the
+ // server computes its own expected axis count from the mode and zeros anything
+ // not packed.
+ size_t num_mode_axes = LLGameControl::numSemanticAxesForMode((LLGameControl::AgentControlMode)state.mActionMode);
+ while (num_mode_axes > 0 && state.mSemanticAxes[num_mode_axes - 1] == 0)
+ {
+ --num_mode_axes;
+ }
+ for (size_t i = 0; i < num_mode_axes; ++i)
+ {
+ msg->nextBlockFast(_PREHASH_ModeAxes);
+ msg->addS16Fast(_PREHASH_Value, state.mSemanticAxes[i]);
+ }
+ if (state.mSemanticButtons != 0)
+ {
+ msg->nextBlockFast(_PREHASH_ModeButtons);
+ msg->addU32Fast(_PREHASH_Flags, state.mSemanticButtons);
+ }
+
+ LLGameControl::updateResendPeriod();
+ gAgent.sendMessage();
+
+ // Mirror the just-sent channel values into the preferences "Data Output" tab.
+ LLPanelPreferenceGameControl::updateDataOutput();
+}
+
bool LLAppViewer::doFrame()
{
+ // SIGTERM asks for a normal logout. Quitting immediately skips
+ // LogoutRequest and leaves the agent in the region.
+ if (LLApp::consumeSignalQuit() && !mQuitRequested && !isQuitting())
+ {
+ LL_INFOS() << "Terminate signal, logging out before exit" << LL_ENDL;
+ requestQuit();
+ }
+
resumeMainloopTimeout("Main:doFrameStart");
+
+ U32 fpsLimitMaxFps = (U32)gSavedSettings.getU32("MaxFPS");
+ if(fpsLimitMaxFps > 120) fpsLimitMaxFps = 0;
+
+ using TimePoint = std::chrono::steady_clock::time_point;
+ U64 additionalSleepTime = 0;
+ TimePoint frameStartTime = std::chrono::steady_clock::now();
+
#ifdef LL_DISCORD
{
LL_PROFILE_ZONE_NAMED("discord_callbacks");
@@ -1404,7 +1537,7 @@ bool LLAppViewer::doFrame()
LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL;
}
- gViewerWindow->getWindow()->gatherInput();
+ gViewerWindow->getWindow()->gatherInput(gFocusMgr.getAppHasFocus());
}
//memory leaking simulation
@@ -1456,6 +1589,11 @@ bool LLAppViewer::doFrame()
joystick->scanJoystick();
gKeyboard->scanKeyboard();
gViewerInput.scanMouse();
+
+ if (gAgent.isCrouching())
+ {
+ gAgent.moveUp(-1);
+ }
}
}
@@ -1532,6 +1670,27 @@ bool LLAppViewer::doFrame()
//LL_RECORD_BLOCK_TIME(SLEEP2);
LL_PROFILE_ZONE_WARN("Sleep2");
+ auto elapsed = std::chrono::steady_clock::now() - frameStartTime;
+ long long frameTime = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
+
+ if(fpsLimitMaxFps > 0)
+ {
+ U64 desired_time_us = (U32)(1000000.f / fpsLimitMaxFps);
+ if((frameTime+1000) < desired_time_us)
+ {
+ additionalSleepTime = 0.92 * (F64)(desired_time_us - frameTime);
+ if(additionalSleepTime < 200)
+ {
+ additionalSleepTime = 0;
+ }
+ }
+ }
+
+ if(additionalSleepTime > 0)
+ {
+ std::this_thread::sleep_for(std::chrono::microseconds(additionalSleepTime));
+ }
+
// yield some time to the os based on command line option
static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1);
if(yield_time >= 0)
@@ -1625,6 +1784,9 @@ bool LLAppViewer::doFrame()
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df resumeMainloopTimeout");
resumeMainloopTimeout();
}
+
+ //swap();
+
pingMainloopTimeout("Main:End");
}
}
@@ -1701,6 +1863,7 @@ void LLAppViewer::flushLFSIO()
bool LLAppViewer::cleanup()
{
+ LLViewerMCP::shutdown();
#if LL_VELOPACK
// Apply any pending Velopack update before shutdown
if (velopack_is_update_pending())
@@ -1714,6 +1877,9 @@ bool LLAppViewer::cleanup()
//ditch LLVOAvatarSelf instance
gAgentAvatarp = NULL;
+ // Sanity check to catch cases where someone forgot to do an RlvActions::isRlvEnabled() check
+ LL_ERRS_IF(!RlvHandler::isEnabled() && RlvHandler::instanceExists()) << "RLV handler instance exists even though RLVa is disabled" << LL_ENDL;
+
LLNotifications::instance().clear();
// workaround for DEV-35406 crash on shutdown
@@ -1737,7 +1903,7 @@ bool LLAppViewer::cleanup()
// one because it happens just after mFastTimerLogThread is deleted. This
// comment is in case we guessed wrong, so we can move it here instead.
-#if LL_LINUX
+#if LL_LINUX || __FreeBSD__
// remove any old breakpad minidump files from the log directory
if (! isError())
{
@@ -2081,6 +2247,8 @@ bool LLAppViewer::cleanup()
LLViewerJoystick::getInstance()->terminate();
}
+ LLGameControl::terminate();
+
LL_INFOS() << "Shutting down message system" << LL_ENDL;
end_messaging_system();
@@ -2695,20 +2863,27 @@ bool LLAppViewer::initConfiguration()
bool success = LLXMLNode::parseFile(settings_file_list, root, NULL);
if (!success)
{
- LL_WARNS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL;
+ std::string parse_error = LLXMLNode::getLastFileError();
+ const std::string& run_context = gDirUtilp->getRunContextDescription();
+
+ LL_WARNS() << "Cannot load default configuration file " << settings_file_list
+ << (parse_error.empty() ? "" : (" - " + parse_error)) << LL_ENDL;
LLError::LLUserWarningMsg::showMissingFiles();
if (gDirUtilp->fileExists(settings_file_list))
{
LL_ERRS() << "Cannot load default configuration file settings_files.xml. "
<< "Please reinstall viewer from https://secondlife.com/support/downloads/ "
- << "and contact https://support.secondlife.com if issue persists after reinstall."
+ << "and contact https://support.secondlife.com if issue persists after reinstall. "
+ << "Reason: " << (parse_error.empty() ? "unknown (file is present but could not be parsed)" : parse_error)
+ << ". Install type: " << run_context
<< LL_ENDL;
}
else
{
LL_ERRS() << "Default configuration file settings_files.xml not found. "
<< "Please reinstall viewer from https://secondlife.com/support/downloads/ "
- << "and contact https://support.secondlife.com if issue persists after reinstall."
+ << "and contact https://support.secondlife.com if issue persists after reinstall. "
+ << "Install type: " << run_context
<< LL_ENDL;
}
}
@@ -3565,7 +3740,7 @@ LLSD LLAppViewer::getViewerInfo() const
url = LLTrans::getString("RELEASE_NOTES_BASE_URL");
if (!LLStringUtil::endsWith(url, "/"))
url += "/";
- url += LLURI::escape(versionInfo.getVersion()) + ".html";
+ url += "#" + LLURI::escape(versionInfo.getVersion()); // + ".html";
}
info["VIEWER_RELEASE_NOTES_URL"] = url;
@@ -3632,6 +3807,7 @@ LLSD LLAppViewer::getViewerInfo() const
}
#endif
+ info["RLV_VERSION"] = RlvActions::isRlvEnabled() ? Rlv::Strings::getVersionAbout() : "(disabled)";
info["OPENGL_VERSION"] = ll_safe_string((const char*)(glGetString(GL_VERSION)));
// Settings
@@ -3677,6 +3853,7 @@ LLSD LLAppViewer::getViewerInfo() const
info["VOICE_VERSION"] = LLTrans::getString("NotConnected");
}
+#if defined(LL_CEF)
std::ostringstream cef_ver_codec;
cef_ver_codec << "Dullahan: ";
cef_ver_codec << DULLAHAN_VERSION_MAJOR;
@@ -3702,7 +3879,9 @@ LLSD LLAppViewer::getViewerInfo() const
cef_ver_codec << CHROME_VERSION_PATCH;
info["LIBCEF_VERSION"] = cef_ver_codec.str();
+#endif
+#if defined(LL_VLC)
std::ostringstream vlc_ver_codec;
vlc_ver_codec << LIBVLC_VERSION_MAJOR;
vlc_ver_codec << ".";
@@ -3710,6 +3889,7 @@ LLSD LLAppViewer::getViewerInfo() const
vlc_ver_codec << ".";
vlc_ver_codec << LIBVLC_VERSION_REVISION;
info["LIBVLC_VERSION"] = vlc_ver_codec.str();
+#endif
LLTrace::Recording& recording = LLViewerStats::instance().getRecording();
S32 packets_in = (S32)recording.getSum(LLStatViewer::PACKETS_IN);
@@ -4854,6 +5034,7 @@ void LLAppViewer::loadKeyBindings()
}
}
LLUrlRegistry::instance().setKeybindingHandler(&gViewerInput);
+ LLUrlRegistry::instance().setGameControllerHandler(LLGameControl::getInstance());
}
// As per GHI #4498, remove old, stale CEF cache folders from previous sessions
@@ -5210,6 +5391,7 @@ void LLAppViewer::idle()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
pingMainloopTimeout("Main:Idle");
+ LLViewerMCP::pump();
// Update frame timers
static LLTimer idle_timer;
@@ -5326,6 +5508,68 @@ void LLAppViewer::idle()
gAgent.autoPilot(&yaw);
}
+ // Auto-derive the active game-control mode (Avatar/Captive/FlyCam) from
+ // current avatar state so the runtime mappings and gating track it.
+ gAgent.updateGameControlMode();
+
+ // Read the agent's control flags now, before applyExternalActions() below
+ // (which drives the avatar from a real game controller) has a chance to
+ // fold any controller-driven movement into them this frame -- so the
+ // keyboard-derived GameControl state computed here can never be sourced
+ // from the controller's own output. See LLGameControllerManager::
+ // setExternalInput()/accumulateFinalState() for where the two are
+ // combined (only as fully-independent final ServerStates).
+ U32 control_flags = gAgent.getControlFlags();
+
+ // apply to GameControl
+ LLGameControl::setExternalInput(control_flags, gAgent.getGameControlButtonsFromKeys(), gAgent.getRunning());
+
+ // Feed the actual on-screen cursor position to GameControl
+ // Matches the same whole-window clamp LLViewerWindow::moveCursorTo()
+ // uses to keep a gamepad-driven cursor on-screen.
+ if (LLGameControl::getAgentControlMode() == LLGameControl::CONTROL_MODE_CURSOR)
+ {
+ LLCoordGL cursor_pos = gViewerWindow->getCurrentMouse();
+ S32 rect_width = gViewerWindow->getWindowWidthScaled();
+ S32 rect_height = gViewerWindow->getWindowHeightScaled();
+ S32 pixel_x = llclamp(cursor_pos.mX, 0, rect_width);
+ S32 pixel_y = llclamp(rect_height - cursor_pos.mY, 0, rect_height);
+ LLGameControl::setMouseCursorPosition(pixel_x, pixel_y, rect_width, rect_height);
+ }
+
+ if (LLPanelPreferenceGameControl::isWaitingForInputChannel())
+ {
+ LLPanelPreferenceGameControl::applyGameControlInput();
+ }
+ else
+ {
+ // Recompute canonical controller state (also populates the internal
+ // state consumed below) and send it to the server when it changed,
+ // but only if the agent's region advertises support for it (the
+ // "GameControlEnabled" simulator feature). While unsupported the
+ // resend deadline is left untouched, so the first frame after the
+ // feature appears sends immediately.
+ if (LLGameControl::computeFinalStateAndCheckForChanges())
+ {
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp && regionp->gameControlEnabled())
+ {
+ sendGameControlData();
+ }
+ }
+
+ // Drive the local avatar from the controller. In Avatar/Captive
+ // modes this moves the avatar; in FlyCam mode applyExternalActions
+ // ignores movement bits (it early-returns while flycam is active) but
+ // still services the flycam on/off toggle, so we run it either way.
+ // Flycam *motion* is driven separately below via gAgent.updateFlycam().
+ if (LLGameControl::willControlAvatar() || LLGameControl::willControlFlycam())
+ {
+ LLGameControl::AgentActions game_control_actions = LLGameControl::computeAgentActions();
+ gAgent.applyExternalActions(game_control_actions);
+ }
+ }
+
send_agent_update(false);
// After calling send_agent_update() in the mainloop we always clear
@@ -5593,9 +5837,14 @@ void LLAppViewer::idle()
{
gAgentPilot.moveCamera();
}
- else if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ else if (gAgent.isUsingFlycam())
{
+ // Flycam is now a single shared state (LLAgentCamera) driven by
+ // whichever input sources are actually present; each is a no-op
+ // when its device/mode isn't active, so it's safe to feed both
+ // every frame rather than picking one exclusively.
LLViewerJoystick::getInstance()->moveFlycam();
+ gAgent.updateFlycam();
}
else
{
@@ -6572,7 +6821,7 @@ void LLAppViewer::initDiscordSocial()
gDiscordPartyMaxSize = 0;
gDiscordTimestampsStart = time(nullptr);
gDiscordClient = std::make_shared<discordpp::Client>();
- gDiscordClient->SetApplicationId(1394782217405862001);
+ gDiscordClient->SetApplicationId(1393451183741599796);
updateDiscordActivity();
}