summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorAndrew Meadows <andrew.l.meadows@gmail.com>2024-09-13 11:48:51 -0700
committerGitHub <noreply@github.com>2024-09-13 11:48:51 -0700
commit2f38f0685cf3031f6108de2a7c312aa4cf0462bd (patch)
treebdc9e145b111a4e73c773c667315ea14bd1ca5f0 /indra/newview
parent74205607b7e106f3b7566ef4a4b9c2fcdfa2f83e (diff)
parentda87e8bd370ea079576f8b412a4ddb80c0715bd1 (diff)
Merge pull request #2569 from secondlife/leviathan/send_agent_update
send AgentUpdate ASAP when control bits change
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llagent.cpp54
-rw-r--r--indra/newview/llagent.h4
-rw-r--r--indra/newview/llagentcamera.cpp4
-rw-r--r--indra/newview/llappviewer.cpp38
-rw-r--r--indra/newview/llappviewer.h6
-rw-r--r--indra/newview/llviewermessage.cpp333
6 files changed, 171 insertions, 268 deletions
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 7c37cc1c00..c8b0adbaf8 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -439,8 +439,6 @@ LLAgent::LLAgent() :
mIsDoNotDisturb(false),
mControlFlags(0x00000000),
- mbFlagsDirty(false),
- mbFlagsNeedReset(false),
mAutoPilot(false),
mAutoPilotFlyOnStop(false),
@@ -936,8 +934,6 @@ void LLAgent::setFlying(bool fly, bool fail_sound)
// Update Movement Controls according to Fly mode
LLFloaterMove::setFlyingMode(fly);
-
- mbFlagsDirty = true;
}
@@ -1068,7 +1064,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
{
regionp->setCapabilitiesReceivedCallback(LLAgent::capabilityReceivedCallback);
}
-
}
else
{
@@ -1556,7 +1551,6 @@ U32 LLAgent::getControlFlags()
void LLAgent::setControlFlags(U32 mask)
{
mControlFlags |= mask;
- mbFlagsDirty = true;
}
@@ -1565,28 +1559,7 @@ void LLAgent::setControlFlags(U32 mask)
//-----------------------------------------------------------------------------
void LLAgent::clearControlFlags(U32 mask)
{
- U32 old_flags = mControlFlags;
mControlFlags &= ~mask;
- if (old_flags != mControlFlags)
- {
- mbFlagsDirty = true;
- }
-}
-
-//-----------------------------------------------------------------------------
-// controlFlagsDirty()
-//-----------------------------------------------------------------------------
-bool LLAgent::controlFlagsDirty() const
-{
- return mbFlagsDirty;
-}
-
-//-----------------------------------------------------------------------------
-// enableControlFlagReset()
-//-----------------------------------------------------------------------------
-void LLAgent::enableControlFlagReset()
-{
- mbFlagsNeedReset = true;
}
//-----------------------------------------------------------------------------
@@ -1594,14 +1567,9 @@ void LLAgent::enableControlFlagReset()
//-----------------------------------------------------------------------------
void LLAgent::resetControlFlags()
{
- if (mbFlagsNeedReset)
- {
- mbFlagsNeedReset = false;
- mbFlagsDirty = false;
- // reset all of the ephemeral flags
- // some flags are managed elsewhere
- mControlFlags &= AGENT_CONTROL_AWAY | AGENT_CONTROL_FLY | AGENT_CONTROL_MOUSELOOK;
- }
+ // reset all of the ephemeral flags
+ // some flags are managed elsewhere
+ mControlFlags &= AGENT_CONTROL_AWAY | AGENT_CONTROL_FLY | AGENT_CONTROL_MOUSELOOK;
}
//-----------------------------------------------------------------------------
@@ -2085,11 +2053,19 @@ void LLAgent::propagate(const F32 dt)
}
// handle rotation based on keyboard levels
- const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
- yaw(YAW_RATE * gAgentCamera.getYawKey() * dt);
+ constexpr F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
+ F32 angle = YAW_RATE * gAgentCamera.getYawKey() * dt;
+ if (fabs(angle) > 0.0f)
+ {
+ yaw(angle);
+ }
- const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
- pitch(PITCH_RATE * gAgentCamera.getPitchKey() * dt);
+ constexpr F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
+ angle = PITCH_RATE * gAgentCamera.getPitchKey() * dt;
+ if (fabs(angle) > 0.0f)
+ {
+ pitch(angle);
+ }
// handle auto-land behavior
if (isAgentAvatarValid())
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 7c7f7aa91d..afc34f747f 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -482,21 +482,17 @@ public:
void setControlFlags(U32 mask); // Performs bitwise mControlFlags |= mask
void clearControlFlags(U32 mask); // Performs bitwise mControlFlags &= ~mask
bool controlFlagsDirty() const;
- void enableControlFlagReset();
void resetControlFlags();
bool anyControlGrabbed() const; // True iff a script has taken over a control
bool isControlGrabbed(S32 control_index) const;
// Send message to simulator to force grabbed controls to be
// released, in case of a poorly written script.
void forceReleaseControls();
- void setFlagsDirty() { mbFlagsDirty = true; }
private:
S32 mControlsTakenCount[TOTAL_CONTROLS];
S32 mControlsTakenPassedOnCount[TOTAL_CONTROLS];
U32 mControlFlags; // Replacement for the mFooKey's
- bool mbFlagsDirty;
- bool mbFlagsNeedReset; // ! HACK ! For preventing incorrect flags sent when crossing region boundaries
//--------------------------------------------------------------------
// Animations
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index e7531f963b..81e79a2ed9 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -2204,10 +2204,6 @@ void LLAgentCamera::changeCameraToMouselook(bool animate)
mCameraMode = CAMERA_MODE_MOUSELOOK;
const U32 old_flags = gAgent.getControlFlags();
gAgent.setControlFlags(AGENT_CONTROL_MOUSELOOK);
- if (old_flags != gAgent.getControlFlags())
- {
- gAgent.setFlagsDirty();
- }
if (animate)
{
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 4eb4f5ae20..764e52accb 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -642,8 +642,6 @@ LLAppViewer::LLAppViewer()
mQuitRequested(false),
mClosingFloaters(false),
mLogoutRequestSent(false),
- mLastAgentControlFlags(0),
- mLastAgentForceUpdate(0),
mMainloopTimeout(NULL),
mAgentRegionLastAlive(false),
mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", false)),
@@ -4711,30 +4709,13 @@ void LLAppViewer::idle()
gAgent.autoPilot(&yaw);
}
- static LLFrameTimer agent_update_timer;
-
- // When appropriate, update agent location to the simulator.
- F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
- F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time;
- bool timed_out = agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND);
- bool force_send =
- // if there is something to send
- (gAgent.controlFlagsDirty() && timed_out)
- // if something changed
- || (mLastAgentControlFlags != gAgent.getControlFlags())
- // keep alive
- || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND));
- // timing out doesn't warranty that an update will be sent,
- // just that it will be checked.
- if (force_send || timed_out)
- {
- LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- // Send avatar and camera info
- mLastAgentControlFlags = gAgent.getControlFlags();
- mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time;
- send_agent_update(force_send);
- agent_update_timer.reset();
- }
+ send_agent_update(false);
+
+ // After calling send_agent_update() in the mainloop we always clear
+ // the agent's ephemeral ControlFlags (whether an AgentUpdate was
+ // actually sent or not) because these will be recomputed based on
+ // real-time key/controller input and resubmitted next frame.
+ gAgent.resetControlFlags();
}
//////////////////////////////////////
@@ -5346,11 +5327,6 @@ void LLAppViewer::idleNetwork()
}
#endif
-
-
- // we want to clear the control after sending out all necessary agent updates
- gAgent.resetControlFlags();
-
// Decode enqueued messages...
S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 7b456cc542..4ce4259ed8 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -322,8 +322,6 @@ private:
bool mQuitRequested; // User wants to quit, may have modified documents open.
bool mClosingFloaters;
bool mLogoutRequestSent; // Disconnect message sent to simulator, no longer safe to send messages to the sim.
- U32 mLastAgentControlFlags;
- F32 mLastAgentForceUpdate;
struct SettingsFiles* mSettingsLocationList;
LLWatchdogTimeout* mMainloopTimeout;
@@ -341,10 +339,6 @@ private:
bool mIsFirstRun;
};
-// consts from viewer.h
-const S32 AGENT_UPDATES_PER_SECOND = 125; // Value derived experimentally to avoid Input Delays with latest PBR-Capable Viewers when viewer FPS is highly volatile.
-const S32 AGENT_FORCE_UPDATES_PER_SECOND = 1;
-
// Globals with external linkage. From viewer.h
// *NOTE:Mani - These will be removed as the Viewer App Cleanup project continues.
//
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 872a9a1581..0861b439eb 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3139,14 +3139,9 @@ void process_crossed_region(LLMessageSystem* msg, void**)
}
-
-// Sends avatar and camera information to simulator.
-// Sent roughly once per frame, or 20 times per second, whichever is less often
-
-const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot
-const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot
- // between these values we delay the updates (but no more than one second)
-
+// sends an AgentUpdate message to the server... or not:
+// only when force_send is 'true' OR
+// something changed AND the update is not being throttled
void send_agent_update(bool force_send, bool send_reliable)
{
LL_PROFILE_ZONE_SCOPED;
@@ -3154,72 +3149,46 @@ void send_agent_update(bool force_send, bool send_reliable)
if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
{
- // We don't care if they want to send an agent update, they're not allowed to until the simulator
- // that's the target is ready to receive them (after avatar_init_complete is received)
+ // We don't care if they want to send an agent update, they're not allowed
+ // until the target simulator is ready to receive them
+ // (e.g. after avatar_init_complete is received)
return;
}
- // We have already requested to log out. Don't send agent updates.
- if(LLAppViewer::instance()->logoutRequestSent())
+ if (LLAppViewer::instance()->logoutRequestSent())
{
+ // We have already requested to log out. Don't send agent updates.
return;
}
- // no region to send update to
- if(gAgent.getRegion() == NULL)
+ if (gAgent.getRegion() == nullptr || gDisconnected)
{
+ // no region to send update to
return;
}
- const F32 TRANSLATE_THRESHOLD = 0.01f;
-
- // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation
- // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change
- // Thus, we're actually testing against 0.2 degrees
- const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above
-
- const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent
-
- // Store data on last sent update so that if no changes, no send
- static LLVector3 last_camera_pos_agent,
- last_camera_at,
- last_camera_left,
- last_camera_up;
-
- static LLVector3 cam_center_chg,
- cam_rot_chg;
-
- static LLQuaternion last_head_rot;
- static U32 last_control_flags = 0;
- static U8 last_render_state;
- static U8 duplicate_count = 0;
- static F32 head_rot_chg = 1.0;
- static U8 last_flags;
-
- LLMessageSystem *msg = gMessageSystem;
- LLVector3 camera_pos_agent; // local to avatar's region
- U8 render_state;
-
- LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion();
- LLQuaternion head_rotation = gAgent.getHeadRotation();
-
- camera_pos_agent = gAgentCamera.getCameraPositionAgent();
+ static F64 last_send_time = 0.0;
+ static U32 last_control_flags = 0;
+ static U8 last_render_state = 0;
+ static U8 last_flags = AU_FLAGS_NONE;
+ static LLQuaternion last_body_rot,
+ last_head_rot;
+ static LLVector3 last_camera_pos_agent,
+ last_camera_at;
- render_state = gAgent.getRenderState();
-
- U32 control_flag_change = 0;
- U8 flag_change = 0;
-
- cam_center_chg = last_camera_pos_agent - camera_pos_agent;
- cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis();
+ // compute sec_since_last_send
+ constexpr F64 MAX_AGENT_UPDATES_PER_SECOND = 125.0; // Value derived experimentally to avoid Input Delays with latest PBR-Capable Viewers when viewer FPS is highly volatile.
+ constexpr F64 MIN_AGENT_UPDATES_PER_SECOND = 1.0; // keep-alive rate
+ constexpr F64 MIN_AGENT_UPDATE_PERIOD = 1.0 / MAX_AGENT_UPDATES_PER_SECOND;
+ constexpr F64 MAX_AGENT_UPDATE_PERIOD = 1.0 / MIN_AGENT_UPDATES_PER_SECOND;
+ F64 now = LLFrameTimer::getTotalSeconds();
+ F64 sec_since_last_send = now - last_send_time;
// If a modifier key is held down, turn off
// LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't
// trigger a control event.
U32 control_flags = gAgent.getControlFlags();
-
- MASK key_mask = gKeyboard->currentMask(true);
-
+ MASK key_mask = gKeyboard->currentMask(true);
if (key_mask & MASK_ALT || key_mask & MASK_CONTROL)
{
control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN |
@@ -3228,7 +3197,22 @@ void send_agent_update(bool force_send, bool send_reliable)
AGENT_CONTROL_ML_LBUTTON_UP ;
}
- control_flag_change = last_control_flags ^ control_flags;
+ // any change in control_flags should be sent ASAP, so we fold that into force_send
+ force_send = force_send || (control_flags != last_control_flags);
+
+ if (! force_send && sec_since_last_send < MIN_AGENT_UPDATE_PERIOD)
+ {
+ // throttle less-important AgentUpdates
+ return;
+ }
+
+ bool send_update = force_send || sec_since_last_send > MAX_AGENT_UPDATE_PERIOD;
+
+ LLVector3 camera_pos_agent = gAgentCamera.getCameraPositionAgent(); // local to avatar's region
+ LLVector3 camera_at = LLViewerCamera::getInstance()->getAtAxis();
+ LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion();
+ LLQuaternion head_rotation = gAgent.getHeadRotation();
+ U8 render_state = gAgent.getRenderState();
U8 flags = AU_FLAGS_NONE;
if (gAgent.isGroupTitleHidden())
@@ -3240,159 +3224,140 @@ void send_agent_update(bool force_send, bool send_reliable)
flags |= AU_FLAGS_CLIENT_AUTOPILOT;
}
- flag_change = last_flags ^ flags;
-
- head_rot_chg = dot(last_head_rot, head_rotation);
-
- //static S32 msg_number = 0; // Used for diagnostic log messages
-
- if (force_send ||
- (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) ||
- (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) ||
- (last_render_state != render_state) ||
- (cam_rot_chg.magVec() > ROTATION_THRESHOLD) ||
- control_flag_change != 0 ||
- flag_change != 0)
+ if (!send_update)
{
- /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block
- msg_number += 1;
- if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT)
- {
- //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL;
- LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL;
- }
- if (cam_rot_chg.magVec() > ROTATION_THRESHOLD)
- {
- LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL;
- }
- if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD)
- {
- LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL;
- }
-// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD)
-// {
-// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL;
-// }
- if (control_flag_change)
+ // check to see if anything changed
+ // use a do-while-false to provide easy way to break out as soon as we find something changed
+ do
{
- LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL;
- }
-*/
-
- duplicate_count = 0;
- }
- else
- {
- duplicate_count++;
+ // start with the easy evaluations and progress to more complicated
- if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND)
- {
- // The head_rotation is sent for updating things like attached guns.
- // We only trigger a new update when head_rotation deviates beyond
- // some threshold from the last update, however this can break fine
- // adjustments when trying to aim an attached gun, so what we do here
- // (where we would normally skip sending an update when nothing has changed)
- // is gradually reduce the threshold to allow a better update to
- // eventually get sent... should update to within 0.5 degrees in less
- // than a second.
- if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND)
+ // check render_state
+ if (last_render_state != render_state)
{
- duplicate_count = 0;
+ send_update = true;
+ break;
}
- else
+
+ // check flags
+ if (last_flags != flags)
{
- return;
+ send_update = true;
+ break;
}
- }
- else
- {
- return;
- }
- }
- if (duplicate_count < DUP_MSGS && !gDisconnected)
- {
- /* More diagnostics to count AgentUpdate messages
- static S32 update_sec = 0;
- static S32 update_count = 0;
- static S32 max_update_count = 0;
- S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() );
- update_count += 1;
- if (cur_sec != update_sec)
- {
- if (update_sec != 0)
+ // check translation
+ constexpr F32 TRANSLATE_THRESHOLD = 0.01f;
+ if ((last_camera_pos_agent - camera_pos_agent).magVec() > TRANSLATE_THRESHOLD)
{
- update_sec = cur_sec;
- //msg_number = 0;
- max_update_count = llmax(max_update_count, update_count);
- LL_INFOS() << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << LL_ENDL;
+ send_update = true;
+ break;
}
- update_sec = cur_sec;
- update_count = 0;
- }
- */
- // Build the message
- msg->newMessageFast(_PREHASH_AgentUpdate);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addQuatFast(_PREHASH_BodyRotation, body_rotation);
- msg->addQuatFast(_PREHASH_HeadRotation, head_rotation);
- msg->addU8Fast(_PREHASH_State, render_state);
- msg->addU8Fast(_PREHASH_Flags, flags);
-
-// if (camera_pos_agent.mV[VY] > 255.f)
-// {
-// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL;
-// }
-
- msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent);
- msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis());
- msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis());
- msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis());
- msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance);
+ // check camera rotation
+ // Note: we are using the sine small angle approximation trick here
+ constexpr F32 RADIANS_PER_DEGREE = F_PI / 360.f;
+ constexpr F32 CAMERA_AT_THRESHOLD = 0.2f * RADIANS_PER_DEGREE;
+ if ((last_camera_at - camera_at).magVec() > CAMERA_AT_THRESHOLD)
+ {
+ send_update = true;
+ break;
+ }
- msg->addU32Fast(_PREHASH_ControlFlags, control_flags);
+ // check head rotation
+ constexpr F64 MIN_HEAD_ROT_QDOT = 0.9997; // ~= 2.5 degrees -- if its less than this we need to update head_rot
+ constexpr F64 MAX_HEAD_ROT_QDOT = 0.99999; // ~= 0.5 degrees -- if its greater than this then we consider it close enough
- if (gDebugClicks)
- {
- if (control_flags & AGENT_CONTROL_LBUTTON_DOWN)
+ if (fabs((F64)(dot(last_body_rot, body_rotation))) < MIN_HEAD_ROT_QDOT)
{
- LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL;
+ send_update = true;
+ break;
}
- if (control_flags & AGENT_CONTROL_LBUTTON_UP)
+ F64 head_rot_qdot = fabs((F64)(dot(last_head_rot, head_rotation)));
+ if (head_rot_qdot > MAX_HEAD_ROT_QDOT)
{
- LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL;
+ // close enough
+ return;
+ }
+ else if (head_rot_qdot < MIN_HEAD_ROT_QDOT)
+ {
+ // way off
+ send_update = true;
+ break;
}
- }
- gAgent.enableControlFlagReset();
+ // Finally, if we get here then head_rot_qdot is somewhere between MIN_ and MAX_HEAD_ROT_QDOT
- if (!send_reliable)
+ // The head_rotation is sent for updating things like attached guns.
+ // We only trigger a new update when head_rotation deviates beyond
+ // some threshold from the last update, however this can break fine
+ // adjustments when trying to aim an attached gun, so what we do here
+ // (where we would normally skip sending an update when nothing has changed)
+ // is linearly increase the min threshold until an update is sent.
+ // Min threshold should update to MAX_HEAD_ROT_QDOT within THRESHOLD_GROWTH_PERIOD.
+ constexpr F64 THRESHOLD_GROWTH_PERIOD = 0.5;
+ constexpr F64 threshold_growth_per_sec = (MAX_HEAD_ROT_QDOT - MIN_HEAD_ROT_QDOT) / THRESHOLD_GROWTH_PERIOD;
+ send_update = head_rot_qdot < MIN_HEAD_ROT_QDOT + sec_since_last_send * threshold_growth_per_sec;
+ } while (false);
+ }
+
+ if (!send_update)
+ {
+ return;
+ }
+
+ // Build the message
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_AgentUpdate);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addQuatFast(_PREHASH_BodyRotation, body_rotation);
+ msg->addQuatFast(_PREHASH_HeadRotation, head_rotation);
+ msg->addU8Fast(_PREHASH_State, render_state);
+ msg->addU8Fast(_PREHASH_Flags, flags);
+
+ msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent);
+ msg->addVector3Fast(_PREHASH_CameraAtAxis, camera_at);
+ msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis());
+ msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis());
+ msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance);
+
+ msg->addU32Fast(_PREHASH_ControlFlags, control_flags);
+
+ if (gDebugClicks)
+ {
+ if (control_flags & AGENT_CONTROL_LBUTTON_DOWN)
{
- gAgent.sendMessage();
+ LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL;
}
- else
+
+ if (control_flags & AGENT_CONTROL_LBUTTON_UP)
{
- gAgent.sendReliableMessage();
+ LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL;
}
+ }
-// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL;
-
- // Copy the old data
- last_head_rot = head_rotation;
- last_render_state = render_state;
- last_camera_pos_agent = camera_pos_agent;
- last_camera_at = LLViewerCamera::getInstance()->getAtAxis();
- last_camera_left = LLViewerCamera::getInstance()->getLeftAxis();
- last_camera_up = LLViewerCamera::getInstance()->getUpAxis();
- last_control_flags = control_flags;
- last_flags = flags;
+ if (send_reliable)
+ {
+ gAgent.sendReliableMessage();
+ }
+ else
+ {
+ gAgent.sendMessage();
}
-}
+ // remember last update data
+ last_send_time = now;
+ last_control_flags = control_flags;
+ last_render_state = render_state;
+ last_flags = flags;
+ last_body_rot = body_rotation;
+ last_head_rot = head_rotation;
+ last_camera_pos_agent = camera_pos_agent;
+ last_camera_at = camera_at;
+}
// sounds can arrive before objects, store them for a short time
// Note: this is a workaround for MAINT-4743, real fix would be to make