/indra/newview/llagentlistener.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 509 lines · 402 code · 53 blank · 54 comment · 43 complexity · a2a9dbe6dc8d4be2d94dbf4f50277ac9 MD5 · raw file

  1. /**
  2. * @file llagentlistener.cpp
  3. * @author Brad Kittenbrink
  4. * @date 2009-07-10
  5. * @brief Implementation for llagentlistener.
  6. *
  7. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "llviewerprecompiledheaders.h"
  29. #include "llagentlistener.h"
  30. #include "llagent.h"
  31. #include "llvoavatar.h"
  32. #include "llcommandhandler.h"
  33. #include "llslurl.h"
  34. #include "llurldispatcher.h"
  35. #include "llviewerobject.h"
  36. #include "llviewerobjectlist.h"
  37. #include "llviewerregion.h"
  38. #include "llsdutil.h"
  39. #include "llsdutil_math.h"
  40. #include "lltoolgrab.h"
  41. #include "llhudeffectlookat.h"
  42. #include "llagentcamera.h"
  43. LLAgentListener::LLAgentListener(LLAgent &agent)
  44. : LLEventAPI("LLAgent",
  45. "LLAgent listener to (e.g.) teleport, sit, stand, etc."),
  46. mAgent(agent)
  47. {
  48. add("requestTeleport",
  49. "Teleport: [\"regionname\"], [\"x\"], [\"y\"], [\"z\"]\n"
  50. "If [\"skip_confirmation\"] is true, use LLURLDispatcher rather than LLCommandDispatcher.",
  51. &LLAgentListener::requestTeleport);
  52. add("requestSit",
  53. "[\"obj_uuid\"]: id of object to sit on, use this or [\"position\"] to indicate the sit target"
  54. "[\"position\"]: region position {x, y, z} where to find closest object to sit on",
  55. &LLAgentListener::requestSit);
  56. add("requestStand",
  57. "Ask to stand up",
  58. &LLAgentListener::requestStand);
  59. add("requestTouch",
  60. "[\"obj_uuid\"]: id of object to touch, use this or [\"position\"] to indicate the object to touch"
  61. "[\"position\"]: region position {x, y, z} where to find closest object to touch"
  62. "[\"face\"]: optional object face number to touch[Default: 0]",
  63. &LLAgentListener::requestTouch);
  64. add("resetAxes",
  65. "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])",
  66. &LLAgentListener::resetAxes);
  67. add("getAxes",
  68. "Obsolete - use getPosition instead\n"
  69. "Send information about the agent's orientation on [\"reply\"]:\n"
  70. "[\"euler\"]: map of {roll, pitch, yaw}\n"
  71. "[\"quat\"]: array of [x, y, z, w] quaternion values",
  72. &LLAgentListener::getAxes,
  73. LLSDMap("reply", LLSD()));
  74. add("getPosition",
  75. "Send information about the agent's position and orientation on [\"reply\"]:\n"
  76. "[\"region\"]: array of region {x, y, z} position\n"
  77. "[\"global\"]: array of global {x, y, z} position\n"
  78. "[\"euler\"]: map of {roll, pitch, yaw}\n"
  79. "[\"quat\"]: array of [x, y, z, w] quaternion values",
  80. &LLAgentListener::getPosition,
  81. LLSDMap("reply", LLSD()));
  82. add("startAutoPilot",
  83. "Start the autopilot system using the following parameters:\n"
  84. "[\"target_global\"]: array of target global {x, y, z} position\n"
  85. "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n"
  86. "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n"
  87. "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n"
  88. "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]"
  89. "[\"allow_flying\"]: allow flying during autopilot [default: True]",
  90. //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n"
  91. //"[\"callback_data\"]: data to send back during a callback [default: none]",
  92. &LLAgentListener::startAutoPilot);
  93. add("getAutoPilot",
  94. "Send information about current state of the autopilot system to [\"reply\"]:\n"
  95. "[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n"
  96. "[\"target_global\"]: array of target global {x, y, z} position\n"
  97. "[\"leader_id\"]: uuid of target autopilot is following\n"
  98. "[\"stop_distance\"]: target maximum distance from target\n"
  99. "[\"target_distance\"]: last known distance from target\n"
  100. "[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n"
  101. "[\"target_facing\"]: array of {x, y} target direction to face\n"
  102. "[\"rotation_threshold\"]: target maximum angle from target facing rotation\n"
  103. "[\"behavior_name\"]: name of the autopilot behavior",
  104. &LLAgentListener::getAutoPilot,
  105. LLSDMap("reply", LLSD()));
  106. add("startFollowPilot",
  107. "[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n"
  108. "[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n"
  109. "[\"allow_flying\"]: allow flying during autopilot [default: True]\n"
  110. "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]",
  111. &LLAgentListener::startFollowPilot);
  112. add("setAutoPilotTarget",
  113. "Update target for currently running autopilot:\n"
  114. "[\"target_global\"]: array of target global {x, y, z} position",
  115. &LLAgentListener::setAutoPilotTarget);
  116. add("stopAutoPilot",
  117. "Stop the autopilot system:\n"
  118. "[\"user_cancel\"] indicates whether or not to act as though user canceled autopilot [default: false]",
  119. &LLAgentListener::stopAutoPilot);
  120. add("lookAt",
  121. "[\"type\"]: number to indicate the lookAt type, 0 to clear\n"
  122. "[\"obj_uuid\"]: id of object to look at, use this or [\"position\"] to indicate the target\n"
  123. "[\"position\"]: region position {x, y, z} where to find closest object or avatar to look at",
  124. &LLAgentListener::lookAt);
  125. }
  126. void LLAgentListener::requestTeleport(LLSD const & event_data) const
  127. {
  128. if(event_data["skip_confirmation"].asBoolean())
  129. {
  130. LLSD params(LLSD::emptyArray());
  131. params.append(event_data["regionname"]);
  132. params.append(event_data["x"]);
  133. params.append(event_data["y"]);
  134. params.append(event_data["z"]);
  135. LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, "clicked", true);
  136. // *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "parcel", "login", login_refresh", "balance", "chat"
  137. // should we just compose LLCommandHandler and LLDispatchListener?
  138. }
  139. else
  140. {
  141. std::string url = LLSLURL(event_data["regionname"],
  142. LLVector3(event_data["x"].asReal(),
  143. event_data["y"].asReal(),
  144. event_data["z"].asReal())).getSLURLString();
  145. LLURLDispatcher::dispatch(url, "clicked", NULL, false);
  146. }
  147. }
  148. void LLAgentListener::requestSit(LLSD const & event_data) const
  149. {
  150. //mAgent.getAvatarObject()->sitOnObject();
  151. // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand()
  152. // *TODO - find a permanent place to share this code properly.
  153. LLViewerObject *object = NULL;
  154. if (event_data.has("obj_uuid"))
  155. {
  156. object = gObjectList.findObject(event_data["obj_uuid"]);
  157. }
  158. else if (event_data.has("position"))
  159. {
  160. LLVector3 target_position = ll_vector3_from_sd(event_data["position"]);
  161. object = findObjectClosestTo(target_position);
  162. }
  163. if (object && object->getPCode() == LL_PCODE_VOLUME)
  164. {
  165. gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
  166. gMessageSystem->nextBlockFast(_PREHASH_AgentData);
  167. gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID());
  168. gMessageSystem->addUUIDFast(_PREHASH_SessionID, mAgent.getSessionID());
  169. gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
  170. gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
  171. gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3(0,0,0));
  172. object->getRegion()->sendReliableMessage();
  173. }
  174. else
  175. {
  176. llwarns << "LLAgent requestSit could not find the sit target: "
  177. << event_data << llendl;
  178. }
  179. }
  180. void LLAgentListener::requestStand(LLSD const & event_data) const
  181. {
  182. mAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
  183. }
  184. LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const
  185. {
  186. LLViewerObject *object = NULL;
  187. // Find the object closest to that position
  188. F32 min_distance = 10000.0f; // Start big
  189. S32 num_objects = gObjectList.getNumObjects();
  190. S32 cur_index = 0;
  191. while (cur_index < num_objects)
  192. {
  193. LLViewerObject * cur_object = gObjectList.getObject(cur_index++);
  194. if (cur_object)
  195. { // Calculate distance from the target position
  196. LLVector3 target_diff = cur_object->getPositionRegion() - position;
  197. F32 distance_to_target = target_diff.length();
  198. if (distance_to_target < min_distance)
  199. { // Found an object closer
  200. min_distance = distance_to_target;
  201. object = cur_object;
  202. }
  203. }
  204. }
  205. return object;
  206. }
  207. void LLAgentListener::requestTouch(LLSD const & event_data) const
  208. {
  209. LLViewerObject *object = NULL;
  210. if (event_data.has("obj_uuid"))
  211. {
  212. object = gObjectList.findObject(event_data["obj_uuid"]);
  213. }
  214. else if (event_data.has("position"))
  215. {
  216. LLVector3 target_position = ll_vector3_from_sd(event_data["position"]);
  217. object = findObjectClosestTo(target_position);
  218. }
  219. S32 face = 0;
  220. if (event_data.has("face"))
  221. {
  222. face = event_data["face"].asInteger();
  223. }
  224. if (object && object->getPCode() == LL_PCODE_VOLUME)
  225. {
  226. // Fake enough pick info to get it to (hopefully) work
  227. LLPickInfo pick;
  228. pick.mObjectFace = face;
  229. /*
  230. These values are sent to the simulator, but face seems to be easiest to use
  231. pick.mUVCoords "UVCoord"
  232. pick.mSTCoords "STCoord"
  233. pick.mObjectFace "FaceIndex"
  234. pick.mIntersection "Position"
  235. pick.mNormal "Normal"
  236. pick.mBinormal "Binormal"
  237. */
  238. // A touch is a sketchy message sequence ... send a grab, immediately
  239. // followed by un-grabbing, crossing fingers and hoping packets arrive in
  240. // the correct order
  241. send_ObjectGrab_message(object, pick, LLVector3::zero);
  242. send_ObjectDeGrab_message(object, pick);
  243. }
  244. else
  245. {
  246. llwarns << "LLAgent requestTouch could not find the touch target "
  247. << event_data["obj_uuid"].asUUID() << llendl;
  248. }
  249. }
  250. void LLAgentListener::resetAxes(const LLSD& event_data) const
  251. {
  252. if (event_data.has("lookat"))
  253. {
  254. mAgent.resetAxes(ll_vector3_from_sd(event_data["lookat"]));
  255. }
  256. else
  257. {
  258. // no "lookat", default call
  259. mAgent.resetAxes();
  260. }
  261. }
  262. void LLAgentListener::getAxes(const LLSD& event_data) const
  263. {
  264. LLQuaternion quat(mAgent.getQuat());
  265. F32 roll, pitch, yaw;
  266. quat.getEulerAngles(&roll, &pitch, &yaw);
  267. // The official query API for LLQuaternion's [x, y, z, w] values is its
  268. // public member mQ...
  269. LLSD reply = LLSD::emptyMap();
  270. reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ));
  271. reply["euler"] = LLSD::emptyMap();
  272. reply["euler"]["roll"] = roll;
  273. reply["euler"]["pitch"] = pitch;
  274. reply["euler"]["yaw"] = yaw;
  275. sendReply(reply, event_data);
  276. }
  277. void LLAgentListener::getPosition(const LLSD& event_data) const
  278. {
  279. F32 roll, pitch, yaw;
  280. LLQuaternion quat(mAgent.getQuat());
  281. quat.getEulerAngles(&roll, &pitch, &yaw);
  282. LLSD reply = LLSD::emptyMap();
  283. reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ));
  284. reply["euler"] = LLSD::emptyMap();
  285. reply["euler"]["roll"] = roll;
  286. reply["euler"]["pitch"] = pitch;
  287. reply["euler"]["yaw"] = yaw;
  288. reply["region"] = ll_sd_from_vector3(mAgent.getPositionAgent());
  289. reply["global"] = ll_sd_from_vector3d(mAgent.getPositionGlobal());
  290. sendReply(reply, event_data);
  291. }
  292. void LLAgentListener::startAutoPilot(LLSD const & event_data)
  293. {
  294. LLQuaternion target_rotation_value;
  295. LLQuaternion* target_rotation = NULL;
  296. if (event_data.has("target_rotation"))
  297. {
  298. target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]);
  299. target_rotation = &target_rotation_value;
  300. }
  301. // *TODO: Use callback_pump and callback_data
  302. F32 rotation_threshold = 0.03f;
  303. if (event_data.has("rotation_threshold"))
  304. {
  305. rotation_threshold = event_data["rotation_threshold"].asReal();
  306. }
  307. BOOL allow_flying = TRUE;
  308. if (event_data.has("allow_flying"))
  309. {
  310. allow_flying = (BOOL) event_data["allow_flying"].asBoolean();
  311. mAgent.setFlying(allow_flying);
  312. }
  313. F32 stop_distance = 0.f;
  314. if (event_data.has("stop_distance"))
  315. {
  316. stop_distance = event_data["stop_distance"].asReal();
  317. }
  318. // Clear follow target, this is doing a path
  319. mFollowTarget.setNull();
  320. mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]),
  321. event_data["behavior_name"],
  322. target_rotation,
  323. NULL, NULL,
  324. stop_distance,
  325. rotation_threshold,
  326. allow_flying);
  327. }
  328. void LLAgentListener::getAutoPilot(const LLSD& event_data) const
  329. {
  330. LLSD reply = LLSD::emptyMap();
  331. LLSD::Boolean enabled = mAgent.getAutoPilot();
  332. reply["enabled"] = enabled;
  333. reply["target_global"] = ll_sd_from_vector3d(mAgent.getAutoPilotTargetGlobal());
  334. reply["leader_id"] = mAgent.getAutoPilotLeaderID();
  335. reply["stop_distance"] = mAgent.getAutoPilotStopDistance();
  336. reply["target_distance"] = mAgent.getAutoPilotTargetDist();
  337. if (!enabled &&
  338. mFollowTarget.notNull())
  339. { // Get an actual distance from the target object we were following
  340. LLViewerObject * target = gObjectList.findObject(mFollowTarget);
  341. if (target)
  342. { // Found the target AV, return the actual distance to them as well as their ID
  343. LLVector3 difference = target->getPositionRegion() - mAgent.getPositionAgent();
  344. reply["target_distance"] = difference.length();
  345. reply["leader_id"] = mFollowTarget;
  346. }
  347. }
  348. reply["use_rotation"] = (LLSD::Boolean) mAgent.getAutoPilotUseRotation();
  349. reply["target_facing"] = ll_sd_from_vector3(mAgent.getAutoPilotTargetFacing());
  350. reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold();
  351. reply["behavior_name"] = mAgent.getAutoPilotBehaviorName();
  352. reply["fly"] = (LLSD::Boolean) mAgent.getFlying();
  353. sendReply(reply, event_data);
  354. }
  355. void LLAgentListener::startFollowPilot(LLSD const & event_data)
  356. {
  357. LLUUID target_id;
  358. BOOL allow_flying = TRUE;
  359. if (event_data.has("allow_flying"))
  360. {
  361. allow_flying = (BOOL) event_data["allow_flying"].asBoolean();
  362. }
  363. if (event_data.has("leader_id"))
  364. {
  365. target_id = event_data["leader_id"];
  366. }
  367. else if (event_data.has("avatar_name"))
  368. { // Find the avatar with matching name
  369. std::string target_name = event_data["avatar_name"].asString();
  370. if (target_name.length() > 0)
  371. {
  372. S32 num_objects = gObjectList.getNumObjects();
  373. S32 cur_index = 0;
  374. while (cur_index < num_objects)
  375. {
  376. LLViewerObject * cur_object = gObjectList.getObject(cur_index++);
  377. if (cur_object &&
  378. cur_object->asAvatar() &&
  379. cur_object->asAvatar()->getFullname() == target_name)
  380. { // Found avatar with matching name, extract id and break out of loop
  381. target_id = cur_object->getID();
  382. break;
  383. }
  384. }
  385. }
  386. }
  387. F32 stop_distance = 0.f;
  388. if (event_data.has("stop_distance"))
  389. {
  390. stop_distance = event_data["stop_distance"].asReal();
  391. }
  392. if (target_id.notNull())
  393. {
  394. mAgent.setFlying(allow_flying);
  395. mFollowTarget = target_id; // Save follow target so we can report distance later
  396. mAgent.startFollowPilot(target_id, allow_flying, stop_distance);
  397. }
  398. }
  399. void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const
  400. {
  401. if (event_data.has("target_global"))
  402. {
  403. LLVector3d target_global(ll_vector3d_from_sd(event_data["target_global"]));
  404. mAgent.setAutoPilotTargetGlobal(target_global);
  405. }
  406. }
  407. void LLAgentListener::stopAutoPilot(LLSD const & event_data) const
  408. {
  409. BOOL user_cancel = FALSE;
  410. if (event_data.has("user_cancel"))
  411. {
  412. user_cancel = event_data["user_cancel"].asBoolean();
  413. }
  414. mAgent.stopAutoPilot(user_cancel);
  415. }
  416. void LLAgentListener::lookAt(LLSD const & event_data) const
  417. {
  418. LLViewerObject *object = NULL;
  419. if (event_data.has("obj_uuid"))
  420. {
  421. object = gObjectList.findObject(event_data["obj_uuid"]);
  422. }
  423. else if (event_data.has("position"))
  424. {
  425. LLVector3 target_position = ll_vector3_from_sd(event_data["position"]);
  426. object = findObjectClosestTo(target_position);
  427. }
  428. S32 look_at_type = (S32) LOOKAT_TARGET_NONE;
  429. if (event_data.has("type"))
  430. {
  431. look_at_type = event_data["type"].asInteger();
  432. }
  433. if (look_at_type >= (S32) LOOKAT_TARGET_NONE &&
  434. look_at_type < (S32) LOOKAT_NUM_TARGETS)
  435. {
  436. gAgentCamera.setLookAt((ELookAtType) look_at_type, object);
  437. }
  438. }
  439. void LLAgentListener::getGroups(const LLSD& event) const
  440. {
  441. LLSD reply(LLSD::emptyArray());
  442. for (LLDynamicArray<LLGroupData>::const_iterator
  443. gi(mAgent.mGroups.begin()), gend(mAgent.mGroups.end());
  444. gi != gend; ++gi)
  445. {
  446. reply.append(LLSDMap
  447. ("id", gi->mID)
  448. ("name", gi->mName)
  449. ("insignia", gi->mInsigniaID)
  450. ("notices", bool(gi->mAcceptNotices))
  451. ("display", bool(gi->mListInProfile))
  452. ("contrib", gi->mContribution));
  453. }
  454. sendReply(LLSDMap("groups", reply), event);
  455. }