summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorMaxim Nikolenko <maximnproductengine@lindenlab.com>2024-09-27 00:25:45 +0300
committerGitHub <noreply@github.com>2024-09-27 00:25:45 +0300
commit813a97c0ab820edaf5ab0fae942c55f1d4b8a36f (patch)
tree68d215295c5fb121cce1122c3f872d85665ced02 /indra
parent51b55e7e85882cde5051d2df6ced8c6a160e04a8 (diff)
parent75d8f732a64e42e8be808a40e8080a226fc91cd9 (diff)
Merge pull request #2700 from secondlife/maxim/lua-autopilot-dev
Lua api for autopilot functions
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/lua_function.cpp4
-rw-r--r--indra/newview/llagentlistener.cpp87
-rw-r--r--indra/newview/llagentlistener.h2
-rw-r--r--indra/newview/scripts/lua/require/LLAgent.lua60
-rw-r--r--indra/newview/scripts/lua/require/LLChat.lua1
-rw-r--r--indra/newview/scripts/lua/require/LLListener.lua (renamed from indra/newview/scripts/lua/require/LLChatListener.lua)24
-rw-r--r--indra/newview/scripts/lua/test_LLChatListener.lua4
-rw-r--r--indra/newview/scripts/lua/test_autopilot.lua22
8 files changed, 158 insertions, 46 deletions
diff --git a/indra/llcommon/lua_function.cpp b/indra/llcommon/lua_function.cpp
index a9f88f3170..33666964f7 100644
--- a/indra/llcommon/lua_function.cpp
+++ b/indra/llcommon/lua_function.cpp
@@ -1150,7 +1150,7 @@ lua_function(check_stop, "check_stop(): ensure that a Lua script responds to vie
* help()
*****************************************************************************/
lua_function(help,
- "LL.help(): list viewer's Lua functions\n"
+ "help(): list viewer's Lua functions\n"
"LL.help(function): show help string for specific function")
{
auto& luapump{ LLEventPumps::instance().obtain("lua output") };
@@ -1210,7 +1210,7 @@ lua_function(help,
*****************************************************************************/
lua_function(
leaphelp,
- "LL.leaphelp(): list viewer's LEAP APIs\n"
+ "leaphelp(): list viewer's LEAP APIs\n"
"LL.leaphelp(api): show help for specific api string name")
{
LLSD request;
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index d9002bf073..14e443ec4e 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -87,33 +87,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",
@@ -205,7 +206,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"))
{
@@ -214,7 +215,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)
@@ -231,8 +238,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");
}
}
@@ -242,7 +248,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;
@@ -253,8 +259,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)
@@ -354,14 +365,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"))
{
@@ -381,13 +391,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);
@@ -395,7 +416,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;
@@ -424,12 +445,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;
@@ -463,6 +483,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"))
@@ -470,13 +494,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
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
index 2765bb5b66..05724ff443 100644
--- a/indra/newview/llagentlistener.h
+++ b/indra/newview/llagentlistener.h
@@ -67,7 +67,7 @@ private:
void stopAnimation(LLSD const &event_data);
void getAnimationInfo(LLSD const &event_data);
- LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const;
+ LLViewerObject * findObjectClosestTo( const LLVector3 & position, bool sit_target = false ) const;
private:
LLAgent & mAgent;
diff --git a/indra/newview/scripts/lua/require/LLAgent.lua b/indra/newview/scripts/lua/require/LLAgent.lua
index 5cee998fcd..4a1132fe7e 100644
--- a/indra/newview/scripts/lua/require/LLAgent.lua
+++ b/indra/newview/scripts/lua/require/LLAgent.lua
@@ -80,4 +80,64 @@ function LLAgent.teleport(...)
return leap.request('LLTeleportHandler', args).message
end
+-- Call with no arguments to sit on the ground.
+-- Otherwise specify "obj_uuid" to sit on,
+-- or region "position" {x, y, z} where to find closest object to sit on.
+-- For example: LLAgent.requestSit{position=LLAgent.getRegionPosition()}
+-- Your avatar should be close enough to the object you want to sit on
+function LLAgent.requestSit(...)
+ local args = mapargs('obj_uuid,position', ...)
+ args.op = 'requestSit'
+ return leap.request('LLAgent', args)
+end
+
+function LLAgent.requestStand()
+ leap.send('LLAgent', {op = 'requestStand'})
+end
+
+-- ***************************************************************************
+-- Autopilot
+-- ***************************************************************************
+LLAgent.autoPilotPump = "LLAutopilot"
+
+-- Start the autopilot to move to "target_global" location using specified parameters
+-- LLAgent.startAutoPilot{ target_global array of target global {x, y, z} position
+-- [, allow_flying] allow flying during autopilot [default: true]
+-- [, stop_distance] target maximum distance from target [default: autopilot guess]
+-- [, behavior_name] name of the autopilot behavior [default: (script name)]
+-- [, target_rotation] array of [x, y, z, w] quaternion values [default: no target]
+-- [, rotation_threshold] target maximum angle from target facing rotation [default: 0.03 radians]
+-- an event with "success" flag is sent to "LLAutopilot" event pump, when auto pilot is terminated
+function LLAgent.startAutoPilot(...)
+ local args = mapargs('target_global,allow_flying,stop_distance,behavior_name,target_rotation,rotation_threshold', ...)
+ args.op = 'startAutoPilot'
+ leap.send('LLAgent', args)
+end
+
+-- Update target location for currently running autopilot
+function LLAgent.setAutoPilotTarget(target_global)
+ leap.send('LLAgent', {op = 'setAutoPilotTarget', target_global=target_global})
+end
+
+-- Start the autopilot to move to the specified target location
+-- either "leader_id" (uuid of target) or "avatar_name" (avatar full name: use just first name for 'Resident') should be specified
+-- "allow_flying" [default: true], "stop_distance" [default: autopilot guess]
+function LLAgent.startFollowPilot(...)
+ local args = mapargs('leader_id,avatar_name,allow_flying,stop_distance', ...)
+ args.op = 'startFollowPilot'
+ return leap.request('LLAgent', args)
+end
+
+-- Stop the autopilot system: "user_cancel" indicates whether or not to act as though user canceled autopilot [default: false]
+function LLAgent.stopAutoPilot(...)
+ local args = mapargs('user_cancel', ...)
+ args.op = 'stopAutoPilot'
+ leap.send('LLAgent', args)
+end
+
+-- Get information about current state of the autopilot
+function LLAgent.getAutoPilot()
+ return leap.request('LLAgent', {op = 'getAutoPilot'})
+end
+
return LLAgent
diff --git a/indra/newview/scripts/lua/require/LLChat.lua b/indra/newview/scripts/lua/require/LLChat.lua
index bc0fc86d22..3ac3bab746 100644
--- a/indra/newview/scripts/lua/require/LLChat.lua
+++ b/indra/newview/scripts/lua/require/LLChat.lua
@@ -5,6 +5,7 @@ local LLChat = {}
-- ***************************************************************************
-- Nearby chat
-- ***************************************************************************
+LLChat.nearbyChatPump = "LLNearbyChat"
-- 0 is public nearby channel, other channels are used to communicate with LSL scripts
function LLChat.sendNearby(msg, channel)
diff --git a/indra/newview/scripts/lua/require/LLChatListener.lua b/indra/newview/scripts/lua/require/LLListener.lua
index 82b28966ce..b05f966097 100644
--- a/indra/newview/scripts/lua/require/LLChatListener.lua
+++ b/indra/newview/scripts/lua/require/LLListener.lua
@@ -3,29 +3,31 @@ local inspect = require 'inspect'
local leap = require 'leap'
local util = require 'util'
-local LLChatListener = {}
+local LLListener = {}
local waitfor = {}
local listener_name = {}
-function LLChatListener:new()
+function LLListener:new(pump_name)
local obj = setmetatable({}, self)
self.__index = self
- obj.name = 'Chat_listener'
+ obj.name = 'Listener:' .. pump_name
+ obj._pump = pump_name
return obj
end
-util.classctor(LLChatListener)
+util.classctor(LLListener)
-function LLChatListener:handleMessages(event_data)
+function LLListener:handleMessages(event_data)
print(inspect(event_data))
return true
end
-function LLChatListener:start()
+function LLListener:start()
+ _pump = self._pump
waitfor = leap.WaitFor(-1, self.name)
function waitfor:filter(pump, data)
- if pump == "LLNearbyChat" then
+ if _pump == pump then
return data
end
end
@@ -37,12 +39,12 @@ function LLChatListener:start()
end
end)
- listener_name = leap.request(leap.cmdpump(), {op='listen', source='LLNearbyChat', listener="ChatListener", tweak=true}).listener
+ listener_name = leap.request(leap.cmdpump(), {op='listen', source=_pump, listener="LLListener", tweak=true}).listener
end
-function LLChatListener:stop()
- leap.send(leap.cmdpump(), {op='stoplistening', source='LLNearbyChat', listener=listener_name})
+function LLListener:stop()
+ leap.send(leap.cmdpump(), {op='stoplistening', source=self._pump, listener=listener_name})
waitfor:close()
end
-return LLChatListener
+return LLListener
diff --git a/indra/newview/scripts/lua/test_LLChatListener.lua b/indra/newview/scripts/lua/test_LLChatListener.lua
index 4a4d40bee5..0f269b54e6 100644
--- a/indra/newview/scripts/lua/test_LLChatListener.lua
+++ b/indra/newview/scripts/lua/test_LLChatListener.lua
@@ -1,4 +1,4 @@
-local LLChatListener = require 'LLChatListener'
+local LLListener = require 'LLListener'
local LLChat = require 'LLChat'
local UI = require 'UI'
@@ -22,7 +22,7 @@ function openOrEcho(message)
end
end
-local listener = LLChatListener()
+local listener = LLListener(LLChat.nearbyChatPump)
function listener:handleMessages(event_data)
if string.find(event_data.message, '[LUA]') then
diff --git a/indra/newview/scripts/lua/test_autopilot.lua b/indra/newview/scripts/lua/test_autopilot.lua
new file mode 100644
index 0000000000..09c85c140a
--- /dev/null
+++ b/indra/newview/scripts/lua/test_autopilot.lua
@@ -0,0 +1,22 @@
+local LLAgent = require 'LLAgent'
+local LLListener = require 'LLListener'
+
+local pos = LLAgent.getGlobalPosition()
+pos[1]+=10 -- delta x
+pos[2]+=5 -- delta y
+LLAgent.requestStand()
+LLAgent.startAutoPilot{target_global=pos,allow_flying=false,stop_distance=1}
+
+local listener = LLListener(LLAgent.autoPilotPump)
+
+function listener:handleMessages(event_data)
+ if event_data.success then
+ print('Destination is reached')
+ LLAgent.requestSit()
+ else
+ print('Failed to reach destination')
+ end
+ return false
+end
+
+listener:start()