summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMnikolenko Productengine <mnikolenko@productengine.com>2025-04-02 17:22:17 +0300
committerMnikolenko Productengine <mnikolenko@productengine.com>2025-04-02 17:22:17 +0300
commitdb2c45ba23a10d34d89f556533f80a8b42600bf6 (patch)
tree6f520194e83afd272f40935d4771dab5ea3c7e6e
parentd77954ef50f300846eb14034a8dde3e4d7064dcf (diff)
#3857 pick new and updated LEAP functions from develop branch
-rw-r--r--indra/newview/llagentlistener.cpp387
-rw-r--r--indra/newview/llagentlistener.h17
-rw-r--r--indra/newview/llfloaterimnearbychat.cpp3
-rw-r--r--indra/newview/llfloaterimnearbychatlistener.cpp34
-rw-r--r--indra/newview/llfloaterimnearbychatlistener.h6
5 files changed, 371 insertions, 76 deletions
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index 0c120ae01d..5ddb87558a 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -31,19 +31,25 @@
#include "llagentlistener.h"
#include "llagent.h"
+#include "llagentcamera.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
#include "llvoavatar.h"
#include "llcommandhandler.h"
+#include "llinventorymodel.h"
#include "llslurl.h"
#include "llurldispatcher.h"
+#include "llviewercontrol.h"
#include "llviewernetwork.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
+#include "llvoavatarself.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "lltoolgrab.h"
#include "llhudeffectlookat.h"
-#include "llagentcamera.h"
+#include "llviewercamera.h"
LLAgentListener::LLAgentListener(LLAgent &agent)
: LLEventAPI("LLAgent",
@@ -69,13 +75,6 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
add("resetAxes",
"Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])",
&LLAgentListener::resetAxes);
- add("getAxes",
- "Obsolete - use getPosition instead\n"
- "Send information about the agent's orientation on [\"reply\"]:\n"
- "[\"euler\"]: map of {roll, pitch, yaw}\n"
- "[\"quat\"]: array of [x, y, z, w] quaternion values",
- &LLAgentListener::getAxes,
- LLSDMap("reply", LLSD()));
add("getPosition",
"Send information about the agent's position and orientation on [\"reply\"]:\n"
"[\"region\"]: array of region {x, y, z} position\n"
@@ -87,33 +86,34 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
add("startAutoPilot",
"Start the autopilot system using the following parameters:\n"
"[\"target_global\"]: array of target global {x, y, z} position\n"
- "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n"
+ "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]\n"
"[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n"
"[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n"
- "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]"
- "[\"allow_flying\"]: allow flying during autopilot [default: True]",
- //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n"
- //"[\"callback_data\"]: data to send back during a callback [default: none]",
- &LLAgentListener::startAutoPilot);
+ "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]\n"
+ "[\"allow_flying\"]: allow flying during autopilot [default: True]\n"
+ "event with [\"success\"] flag is sent to 'LLAutopilot' event pump, when auto pilot is terminated",
+ &LLAgentListener::startAutoPilot,
+ llsd::map("target_global", LLSD()));
add("getAutoPilot",
"Send information about current state of the autopilot system to [\"reply\"]:\n"
"[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n"
"[\"target_global\"]: array of target global {x, y, z} position\n"
"[\"leader_id\"]: uuid of target autopilot is following\n"
- "[\"stop_distance\"]: target maximum distance from target\n"
+ "[\"stop_distance\"]: maximum stop distance from target\n"
"[\"target_distance\"]: last known distance from target\n"
"[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n"
"[\"target_facing\"]: array of {x, y} target direction to face\n"
"[\"rotation_threshold\"]: target maximum angle from target facing rotation\n"
"[\"behavior_name\"]: name of the autopilot behavior",
&LLAgentListener::getAutoPilot,
- LLSDMap("reply", LLSD()));
+ llsd::map("reply", LLSD()));
add("startFollowPilot",
"[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n"
"[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n"
"[\"allow_flying\"]: allow flying during autopilot [default: True]\n"
- "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]",
- &LLAgentListener::startFollowPilot);
+ "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]",
+ &LLAgentListener::startFollowPilot,
+ llsd::map("reply", LLSD()));
add("setAutoPilotTarget",
"Update target for currently running autopilot:\n"
"[\"target_global\"]: array of target global {x, y, z} position",
@@ -138,6 +138,69 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
"[\"contrib\"]: user's land contribution to this group\n",
&LLAgentListener::getGroups,
LLSDMap("reply", LLSD()));
+ //camera params are similar to LSL, see https://wiki.secondlife.com/wiki/LlSetCameraParams
+ add("setCameraParams",
+ "Set Follow camera params, and then activate it:\n"
+ "[\"camera_pos\"]: vector3, camera position in region coordinates\n"
+ "[\"focus_pos\"]: vector3, what the camera is aimed at (in region coordinates)\n"
+ "[\"focus_offset\"]: vector3, adjusts the camera focus position relative to the target, default is (1, 0, 0)\n"
+ "[\"distance\"]: float (meters), distance the camera wants to be from its target, default is 3\n"
+ "[\"focus_threshold\"]: float (meters), sets the radius of a sphere around the camera's target position within which its focus is not affected by target motion, default is 1\n"
+ "[\"camera_threshold\"]: float (meters), sets the radius of a sphere around the camera's ideal position within which it is not affected by target motion, default is 1\n"
+ "[\"focus_lag\"]: float (seconds), how much the camera lags as it tries to aim towards the target, default is 0.1\n"
+ "[\"camera_lag\"]: float (seconds), how much the camera lags as it tries to move towards its 'ideal' position, default is 0.1\n"
+ "[\"camera_pitch\"]: float (degrees), adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance, default is 0\n"
+ "[\"behindness_angle\"]: float (degrees), sets the angle in degrees within which the camera is not constrained by changes in target rotation, default is 10\n"
+ "[\"behindness_lag\"]: float (seconds), sets how strongly the camera is forced to stay behind the target if outside of behindness angle, default is 0\n"
+ "[\"camera_locked\"]: bool, locks the camera position so it will not move\n"
+ "[\"focus_locked\"]: bool, locks the camera focus so it will not move",
+ &LLAgentListener::setFollowCamParams);
+ add("setFollowCamActive",
+ "Turns on or off scripted control of the camera using boolean [\"active\"]",
+ &LLAgentListener::setFollowCamActive,
+ llsd::map("active", LLSD()));
+ add("removeCameraParams",
+ "Reset Follow camera params",
+ &LLAgentListener::removeFollowCamParams);
+
+ add("playAnimation",
+ "Play [\"item_id\"] animation locally (by default) or [\"inworld\"] (when set to true)",
+ &LLAgentListener::playAnimation,
+ llsd::map("item_id", LLSD(), "reply", LLSD()));
+ add("stopAnimation",
+ "Stop playing [\"item_id\"] animation",
+ &LLAgentListener::stopAnimation,
+ llsd::map("item_id", LLSD(), "reply", LLSD()));
+ add("getAnimationInfo",
+ "Return information about [\"item_id\"] animation",
+ &LLAgentListener::getAnimationInfo,
+ llsd::map("item_id", LLSD(), "reply", LLSD()));
+
+ add("getID",
+ "Return your own avatar ID",
+ &LLAgentListener::getID,
+ llsd::map("reply", LLSD()));
+
+ add("getNearbyAvatarsList",
+ "Return result set key [\"result\"] for nearby avatars in a range of [\"dist\"]\n"
+ "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n"
+ "reply contains \"result\" table with \"id\", \"name\", \"global_pos\", \"region_pos\", \"region_id\" fields",
+ &LLAgentListener::getNearbyAvatarsList,
+ llsd::map("reply", LLSD()));
+
+ add("getNearbyObjectsList",
+ "Return result set key [\"result\"] for nearby objects in a range of [\"dist\"]\n"
+ "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n"
+ "reply contains \"result\" table with \"id\", \"global_pos\", \"region_pos\", \"region_id\" fields",
+ &LLAgentListener::getNearbyObjectsList,
+ llsd::map("reply", LLSD()));
+
+ add("getAgentScreenPos",
+ "Return screen position of the [\"avatar_id\"] avatar or own avatar if not specified\n"
+ "reply contains \"x\", \"y\" coordinates and \"onscreen\" flag to indicate if it's actually in within the current window\n"
+ "avatar render position is used as the point",
+ &LLAgentListener::getAgentScreenPos,
+ llsd::map("reply", LLSD()));
}
void LLAgentListener::requestTeleport(LLSD const & event_data) const
@@ -168,7 +231,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
//mAgent.getAvatarObject()->sitOnObject();
// shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand()
// *TODO - find a permanent place to share this code properly.
-
+ Response response(LLSD(), event_data);
LLViewerObject *object = NULL;
if (event_data.has("obj_uuid"))
{
@@ -177,7 +240,13 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
else if (event_data.has("position"))
{
LLVector3 target_position = ll_vector3_from_sd(event_data["position"]);
- object = findObjectClosestTo(target_position);
+ object = findObjectClosestTo(target_position, true);
+ }
+ else
+ {
+ //just sit on the ground
+ mAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+ return;
}
if (object && object->getPCode() == LL_PCODE_VOLUME)
@@ -194,8 +263,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
}
else
{
- LL_WARNS() << "LLAgent requestSit could not find the sit target: "
- << event_data << LL_ENDL;
+ response.error("requestSit could not find the sit target");
}
}
@@ -205,7 +273,7 @@ void LLAgentListener::requestStand(LLSD const & event_data) const
}
-LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const
+LLViewerObject * LLAgentListener::findObjectClosestTo(const LLVector3 & position, bool sit_target) const
{
LLViewerObject *object = NULL;
@@ -216,8 +284,13 @@ LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & positio
while (cur_index < num_objects)
{
LLViewerObject * cur_object = gObjectList.getObject(cur_index++);
- if (cur_object)
- { // Calculate distance from the target position
+ if (cur_object && !cur_object->isAttachment())
+ {
+ if(sit_target && (cur_object->getPCode() != LL_PCODE_VOLUME))
+ {
+ continue;
+ }
+ // Calculate distance from the target position
LLVector3 target_diff = cur_object->getPositionRegion() - position;
F32 distance_to_target = target_diff.length();
if (distance_to_target < min_distance)
@@ -296,22 +369,6 @@ void LLAgentListener::resetAxes(const LLSD& event_data) const
}
}
-void LLAgentListener::getAxes(const LLSD& event_data) const
-{
- LLQuaternion quat(mAgent.getQuat());
- F32 roll, pitch, yaw;
- quat.getEulerAngles(&roll, &pitch, &yaw);
- // The official query API for LLQuaternion's [x, y, z, w] values is its
- // public member mQ...
- LLSD reply = LLSD::emptyMap();
- reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ));
- reply["euler"] = LLSD::emptyMap();
- reply["euler"]["roll"] = roll;
- reply["euler"]["pitch"] = pitch;
- reply["euler"]["yaw"] = yaw;
- sendReply(reply, event_data);
-}
-
void LLAgentListener::getPosition(const LLSD& event_data) const
{
F32 roll, pitch, yaw;
@@ -333,14 +390,13 @@ void LLAgentListener::getPosition(const LLSD& event_data) const
void LLAgentListener::startAutoPilot(LLSD const & event_data)
{
- LLQuaternion target_rotation_value;
LLQuaternion* target_rotation = NULL;
if (event_data.has("target_rotation"))
{
- target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]);
+ LLQuaternion target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]);
target_rotation = &target_rotation_value;
}
- // *TODO: Use callback_pump and callback_data
+
F32 rotation_threshold = 0.03f;
if (event_data.has("rotation_threshold"))
{
@@ -360,13 +416,24 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data)
stop_distance = (F32)event_data["stop_distance"].asReal();
}
+ std::string behavior_name = LLCoros::getName();
+ if (event_data.has("behavior_name"))
+ {
+ behavior_name = event_data["behavior_name"].asString();
+ }
+
// Clear follow target, this is doing a path
mFollowTarget.setNull();
+ auto finish_cb = [](bool success, void*)
+ {
+ LLEventPumps::instance().obtain("LLAutopilot").post(llsd::map("success", success));
+ };
+
mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]),
- event_data["behavior_name"],
+ behavior_name,
target_rotation,
- NULL, NULL,
+ finish_cb, NULL,
stop_distance,
rotation_threshold,
allow_flying);
@@ -374,7 +441,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data)
void LLAgentListener::getAutoPilot(const LLSD& event_data) const
{
- LLSD reply = LLSD::emptyMap();
+ Response reply(LLSD(), event_data);
LLSD::Boolean enabled = mAgent.getAutoPilot();
reply["enabled"] = enabled;
@@ -403,12 +470,11 @@ void LLAgentListener::getAutoPilot(const LLSD& event_data) const
reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold();
reply["behavior_name"] = mAgent.getAutoPilotBehaviorName();
reply["fly"] = (LLSD::Boolean) mAgent.getFlying();
-
- sendReply(reply, event_data);
}
void LLAgentListener::startFollowPilot(LLSD const & event_data)
{
+ Response response(LLSD(), event_data);
LLUUID target_id;
bool allow_flying = true;
@@ -442,6 +508,10 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data)
}
}
}
+ else
+ {
+ return response.error("'leader_id' or 'avatar_name' should be specified");
+ }
F32 stop_distance = 0.f;
if (event_data.has("stop_distance"))
@@ -449,13 +519,16 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data)
stop_distance = (F32)event_data["stop_distance"].asReal();
}
- if (target_id.notNull())
+ if (!gObjectList.findObject(target_id))
{
- mAgent.setFlying(allow_flying);
- mFollowTarget = target_id; // Save follow target so we can report distance later
-
- mAgent.startFollowPilot(target_id, allow_flying, stop_distance);
+ std::string target_info = event_data.has("leader_id") ? event_data["leader_id"] : event_data["avatar_name"];
+ return response.error(stringize("Target ", std::quoted(target_info), " was not found"));
}
+
+ mAgent.setFlying(allow_flying);
+ mFollowTarget = target_id; // Save follow target so we can report distance later
+
+ mAgent.startFollowPilot(target_id, allow_flying, stop_distance);
}
void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const
@@ -519,3 +592,209 @@ void LLAgentListener::getGroups(const LLSD& event) const
}
sendReply(LLSDMap("groups", reply), event);
}
+
+/*----------------------------- camera control -----------------------------*/
+// specialize LLSDParam to support (const LLVector3&) arguments -- this
+// wouldn't even be necessary except that the relevant LLVector3 constructor
+// is explicitly explicit
+template <>
+class LLSDParam<const LLVector3&>: public LLSDParamBase
+{
+public:
+ LLSDParam(const LLSD& value): value(LLVector3(value)) {}
+
+ operator const LLVector3&() const { return value; }
+
+private:
+ LLVector3 value;
+};
+
+// accept any of a number of similar LLFollowCamMgr methods with different
+// argument types, and return a wrapper lambda that accepts LLSD and converts
+// to the target argument type
+template <typename T>
+auto wrap(void (LLFollowCamMgr::*method)(const LLUUID& source, T arg))
+{
+ return [method](LLFollowCamMgr& followcam, const LLUUID& source, const LLSD& arg)
+ { (followcam.*method)(source, LLSDParam<T>(arg)); };
+}
+
+// table of supported LLFollowCamMgr methods,
+// with the corresponding setFollowCamParams() argument keys
+static std::pair<std::string, std::function<void(LLFollowCamMgr&, const LLUUID&, const LLSD&)>>
+cam_params[] =
+{
+ { "camera_pos", wrap(&LLFollowCamMgr::setPosition) },
+ { "focus_pos", wrap(&LLFollowCamMgr::setFocus) },
+ { "focus_offset", wrap(&LLFollowCamMgr::setFocusOffset) },
+ { "camera_locked", wrap(&LLFollowCamMgr::setPositionLocked) },
+ { "focus_locked", wrap(&LLFollowCamMgr::setFocusLocked) },
+ { "distance", wrap(&LLFollowCamMgr::setDistance) },
+ { "focus_threshold", wrap(&LLFollowCamMgr::setFocusThreshold) },
+ { "camera_threshold", wrap(&LLFollowCamMgr::setPositionThreshold) },
+ { "focus_lag", wrap(&LLFollowCamMgr::setFocusLag) },
+ { "camera_lag", wrap(&LLFollowCamMgr::setPositionLag) },
+ { "camera_pitch", wrap(&LLFollowCamMgr::setPitch) },
+ { "behindness_lag", wrap(&LLFollowCamMgr::setBehindnessLag) },
+ { "behindness_angle", wrap(&LLFollowCamMgr::setBehindnessAngle) },
+};
+
+void LLAgentListener::setFollowCamParams(const LLSD& event) const
+{
+ auto& followcam{ LLFollowCamMgr::instance() };
+ for (const auto& pair : cam_params)
+ {
+ if (event.has(pair.first))
+ {
+ pair.second(followcam, gAgentID, event[pair.first]);
+ }
+ }
+ followcam.setCameraActive(gAgentID, true);
+}
+
+void LLAgentListener::setFollowCamActive(LLSD const & event) const
+{
+ LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, event["active"]);
+}
+
+void LLAgentListener::removeFollowCamParams(LLSD const & event) const
+{
+ LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID);
+}
+
+LLViewerInventoryItem* get_anim_item(LLEventAPI::Response &response, const LLSD &event_data)
+{
+ LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID());
+ if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION))
+ {
+ response.error(stringize("Animation item ", std::quoted(event_data["item_id"].asString()), " was not found"));
+ return NULL;
+ }
+ return item;
+}
+
+void LLAgentListener::playAnimation(LLSD const &event_data)
+{
+ Response response(LLSD(), event_data);
+ if (LLViewerInventoryItem* item = get_anim_item(response, event_data))
+ {
+ if (event_data["inworld"].asBoolean())
+ {
+ mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_START);
+ }
+ else
+ {
+ gAgentAvatarp->startMotion(item->getAssetUUID());
+ }
+ }
+}
+
+void LLAgentListener::stopAnimation(LLSD const &event_data)
+{
+ Response response(LLSD(), event_data);
+ if (LLViewerInventoryItem* item = get_anim_item(response, event_data))
+ {
+ gAgentAvatarp->stopMotion(item->getAssetUUID());
+ mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP);
+ }
+}
+
+void LLAgentListener::getAnimationInfo(LLSD const &event_data)
+{
+ Response response(LLSD(), event_data);
+ if (LLViewerInventoryItem* item = get_anim_item(response, event_data))
+ {
+ // if motion exists, will return existing one
+ LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID());
+ response["anim_info"] = llsd::map("duration", motion->getDuration(),
+ "is_loop", motion->getLoop(),
+ "num_joints", motion->getNumJointMotions(),
+ "asset_id", item->getAssetUUID(),
+ "priority", motion->getPriority());
+ }
+}
+
+void LLAgentListener::getID(LLSD const& event_data)
+{
+ Response response(llsd::map("id", gAgentID), event_data);
+}
+
+F32 get_search_radius(LLSD const& event_data)
+{
+ static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64);
+ F32 dist = render_far_clip;
+ if (event_data.has("dist"))
+ {
+ dist = llclamp((F32)event_data["dist"].asReal(), 1, 512);
+ }
+ return dist * dist;
+}
+
+void LLAgentListener::getNearbyAvatarsList(LLSD const& event_data)
+{
+ Response response(LLSD(), event_data);
+ F32 radius = get_search_radius(event_data);
+ LLVector3d agent_pos = gAgent.getPositionGlobal();
+ for (LLCharacter* character : LLCharacter::sInstances)
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*)character;
+ if (avatar && !avatar->isDead() && !avatar->isControlAvatar() && !avatar->isSelf())
+ {
+ if ((dist_vec_squared(avatar->getPositionGlobal(), agent_pos) <= radius))
+ {
+ LLAvatarName av_name;
+ LLAvatarNameCache::get(avatar->getID(), &av_name);
+ LLVector3 region_pos = avatar->getCharacterPosition();
+ response["result"].append(llsd::map("id", avatar->getID(), "global_pos", ll_sd_from_vector3d(avatar->getPosGlobalFromAgent(region_pos)),
+ "region_pos", ll_sd_from_vector3(region_pos), "name", av_name.getUserName(), "region_id", avatar->getRegion()->getRegionID()));
+ }
+ }
+ }
+}
+
+void LLAgentListener::getNearbyObjectsList(LLSD const& event_data)
+{
+ Response response(LLSD(), event_data);
+ F32 radius = get_search_radius(event_data);
+ S32 num_objects = gObjectList.getNumObjects();
+ LLVector3d agent_pos = gAgent.getPositionGlobal();
+ for (S32 i = 0; i < num_objects; ++i)
+ {
+ LLViewerObject* object = gObjectList.getObject(i);
+ if (object && object->getVolume() && !object->isAttachment())
+ {
+ if ((dist_vec_squared(object->getPositionGlobal(), agent_pos) <= radius))
+ {
+ response["result"].append(llsd::map("id", object->getID(), "global_pos", ll_sd_from_vector3d(object->getPositionGlobal()), "region_pos",
+ ll_sd_from_vector3(object->getPositionRegion()), "region_id", object->getRegion()->getRegionID()));
+ }
+ }
+ }
+}
+
+void LLAgentListener::getAgentScreenPos(LLSD const& event_data)
+{
+ Response response(LLSD(), event_data);
+ LLVector3 render_pos;
+ if (event_data.has("avatar_id") && (event_data["avatar_id"].asUUID() != gAgentID))
+ {
+ LLUUID avatar_id(event_data["avatar_id"]);
+ for (LLCharacter* character : LLCharacter::sInstances)
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*)character;
+ if (!avatar->isDead() && (avatar->getID() == avatar_id))
+ {
+ render_pos = avatar->getRenderPosition();
+ break;
+ }
+ }
+ }
+ else if (gAgentAvatarp.notNull() && gAgentAvatarp->isValid())
+ {
+ render_pos = gAgentAvatarp->getRenderPosition();
+ }
+ LLCoordGL screen_pos;
+ response["onscreen"] = LLViewerCamera::getInstance()->projectPosAgentToScreen(render_pos, screen_pos, false);
+ response["x"] = screen_pos.mX;
+ response["y"] = screen_pos.mY;
+}
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
index c544d089ce..31f50a653f 100644
--- a/indra/newview/llagentlistener.h
+++ b/indra/newview/llagentlistener.h
@@ -48,7 +48,6 @@ private:
void requestStand(LLSD const & event_data) const;
void requestTouch(LLSD const & event_data) const;
void resetAxes(const LLSD& event_data) const;
- void getAxes(const LLSD& event_data) const;
void getGroups(const LLSD& event) const;
void getPosition(const LLSD& event_data) const;
void startAutoPilot(const LLSD& event_data);
@@ -58,7 +57,21 @@ private:
void stopAutoPilot(const LLSD& event_data) const;
void lookAt(LLSD const & event_data) const;
- LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const;
+ void setFollowCamParams(LLSD const & event_data) const;
+ void setFollowCamActive(LLSD const & event_data) const;
+ void removeFollowCamParams(LLSD const & event_data) const;
+
+ void playAnimation(LLSD const &event_data);
+ void playAnimation_(const LLUUID& asset_id, const bool inworld);
+ void stopAnimation(LLSD const &event_data);
+ void getAnimationInfo(LLSD const &event_data);
+
+ void getID(LLSD const& event_data);
+ void getNearbyAvatarsList(LLSD const& event_data);
+ void getNearbyObjectsList(LLSD const& event_data);
+ void getAgentScreenPos(LLSD const& event_data);
+
+ LLViewerObject * findObjectClosestTo( const LLVector3 & position, bool sit_target = false ) const;
private:
LLAgent & mAgent;
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 28c651f0cd..db6f9ac22a 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -52,6 +52,7 @@
#include "llfirstuse.h"
#include "llfloaterimnearbychat.h"
+#include "llfloaterimnearbychatlistener.h"
#include "llagent.h" // gAgent
#include "llgesturemgr.h"
#include "llmultigesture.h"
@@ -71,6 +72,8 @@
S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0;
+static LLFloaterIMNearbyChatListener sChatListener;
+
constexpr S32 EXPANDED_HEIGHT = 266;
constexpr S32 COLLAPSED_HEIGHT = 60;
constexpr S32 EXPANDED_MIN_HEIGHT = 150;
diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp
index 43173d3680..b15a32ce40 100644
--- a/indra/newview/llfloaterimnearbychatlistener.cpp
+++ b/indra/newview/llfloaterimnearbychatlistener.cpp
@@ -34,12 +34,12 @@
#include "llagent.h"
#include "llchat.h"
#include "llviewercontrol.h"
+#include "stringize.h"
+static const F32 CHAT_THROTTLE_PERIOD = 1.f;
-LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar)
- : LLEventAPI("LLChatBar",
- "LLChatBar listener to (e.g.) sendChat, etc."),
- mChatbar(chatbar)
+LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() :
+ LLEventAPI("LLChatBar", "LLChatBar listener to (e.g.) sendChat, etc.")
{
add("sendChat",
"Send chat to the simulator:\n"
@@ -49,10 +49,18 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyCh
&LLFloaterIMNearbyChatListener::sendChat);
}
-
// "sendChat" command
-void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const
+void LLFloaterIMNearbyChatListener::sendChat(LLSD const& chat_data)
{
+ F64 cur_time = LLTimer::getElapsedSeconds();
+
+ if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD)
+ {
+ LL_WARNS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL;
+ return;
+ }
+ mLastThrottleTime = cur_time;
+
// Extract the data
std::string chat_text = chat_data["message"].asString();
@@ -81,20 +89,12 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const
}
// Have to prepend /42 style channel numbers
- std::string chat_to_send;
- if (channel == 0)
- {
- chat_to_send = chat_text;
- }
- else
+ if (channel)
{
- chat_to_send += "/";
- chat_to_send += chat_data["channel"].asString();
- chat_to_send += " ";
- chat_to_send += chat_text;
+ chat_text = stringize("/", chat_data["channel"].asString(), " ", chat_text);
}
// Send it as if it was typed in
- mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, ((bool)(channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim"));
+ LLFloaterIMNearbyChat::sendChatFromViewer(chat_text, type_o_chat, (channel == 0) && gSavedSettings.getBOOL("PlayChatAnim"));
}
diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h
index 96184d95b3..71eba53a9a 100644
--- a/indra/newview/llfloaterimnearbychatlistener.h
+++ b/indra/newview/llfloaterimnearbychatlistener.h
@@ -38,12 +38,12 @@ class LLFloaterIMNearbyChat;
class LLFloaterIMNearbyChatListener : public LLEventAPI
{
public:
- LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar);
+ LLFloaterIMNearbyChatListener();
private:
- void sendChat(LLSD const & chat_data) const;
+ void sendChat(LLSD const & chat_data);
- LLFloaterIMNearbyChat & mChatbar;
+ F64 mLastThrottleTime{0};
};
#endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H