#3857 pick new and updated LEAP functions from develop branch

master
Mnikolenko Productengine 2025-04-02 17:22:17 +03:00
parent d77954ef50
commit db2c45ba23
5 changed files with 371 additions and 76 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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)
if (channel)
{
chat_to_send = chat_text;
}
else
{
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"));
}

View File

@ -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