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.cpp196
1 files changed, 190 insertions, 6 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index f8c687b0fc..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
@@ -198,6 +202,7 @@
#include "lldebugview.h"
#include "llconsole.h"
#include "llcontainerview.h"
+#include "lltoolfocus.h"
#include "lltooltip.h"
#include "llsdutil.h"
@@ -224,6 +229,7 @@
#include "llvosurfacepatch.h"
#include "llviewerfloaterreg.h"
#include "llcommandlineparser.h"
+#include "llfloaterpreference.h"
#include "llfloatermemleak.h"
#include "llfloaterreg.h"
#include "llfloatersimplesnapshot.h"
@@ -244,6 +250,7 @@
#include "lldrawpoolbump.h"
#include "llvieweraudio.h"
#include "llimview.h"
+#include "llchatservicehistory.h"
#include "llviewerthrottle.h"
#include "llparcel.h"
#include "llavatariconctrl.h"
@@ -1162,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();
@@ -1271,6 +1303,7 @@ bool LLAppViewer::init()
LLWorld::createInstance();
LLViewerStatsRecorder::createInstance();
LLSelectMgr::createInstance();
+ LLToolCamera::createInstance();
LLViewerCamera::createInstance();
LL::GLTFSceneManager::createInstance();
@@ -1358,6 +1391,66 @@ 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
@@ -1444,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
@@ -1496,6 +1589,11 @@ bool LLAppViewer::doFrame()
joystick->scanJoystick();
gKeyboard->scanKeyboard();
gViewerInput.scanMouse();
+
+ if (gAgent.isCrouching())
+ {
+ gAgent.moveUp(-1);
+ }
}
}
@@ -1765,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())
@@ -2148,6 +2247,8 @@ bool LLAppViewer::cleanup()
LLViewerJoystick::getInstance()->terminate();
}
+ LLGameControl::terminate();
+
LL_INFOS() << "Shutting down message system" << LL_ENDL;
end_messaging_system();
@@ -2762,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;
}
}
@@ -4926,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
@@ -5282,6 +5391,7 @@ void LLAppViewer::idle()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
pingMainloopTimeout("Main:Idle");
+ LLViewerMCP::pump();
// Update frame timers
static LLTimer idle_timer;
@@ -5378,7 +5488,7 @@ void LLAppViewer::idle()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK);
// Update spaceserver timeinfo
- LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw));
+ LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U64)(dt_raw * USEC_PER_SEC));
//////////////////////////////////////
@@ -5398,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
@@ -5665,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
{
@@ -5799,6 +5976,8 @@ void LLAppViewer::idleShutdown()
// All floaters are closed. Tell server we want to quit.
if (!logoutRequestSent())
{
+ // Fence outstanding history work before logout tears down its account and capability context.
+ LLChatServiceHistory::stop();
sendLogoutRequest();
// Wait for a LogoutReply message
@@ -6192,6 +6371,9 @@ void LLAppViewer::idleNetwork()
void LLAppViewer::disconnectViewer()
{
+ // This is idempotent and also covers disconnect paths that bypass the normal logout request.
+ LLChatServiceHistory::stop();
+
if (gDisconnected)
{
return;
@@ -6551,6 +6733,8 @@ void LLAppViewer::handleLoginComplete()
gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
}
+ // Start only after login has established the per-account storage and region capability context.
+ LLChatServiceHistory::start();
mOnLoginCompleted();
writeDebugInfo();