diff options
| author | Rider Linden <rider@lindenlab.com> | 2026-08-06 14:25:45 -0700 |
|---|---|---|
| committer | Rider Linden <rider@lindenlab.com> | 2026-08-06 14:25:45 -0700 |
| commit | 309fc5b4c21151e3664f5bdab99f57bae24266a0 (patch) | |
| tree | d7700857c86f8945d805b848494102cee299ac50 /indra/newview/llscripteditorws.cpp | |
| parent | ebf9cd31d789c0556d741987e95a961edd2955d0 (diff) | |
JSON-RPC command.execute instruction for arbitrary 1-off commands and extensions.
Diffstat (limited to 'indra/newview/llscripteditorws.cpp')
| -rw-r--r-- | indra/newview/llscripteditorws.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/indra/newview/llscripteditorws.cpp b/indra/newview/llscripteditorws.cpp index 8f45d14c36..3fbcd5c384 100644 --- a/indra/newview/llscripteditorws.cpp +++ b/indra/newview/llscripteditorws.cpp @@ -31,6 +31,7 @@ #include "llscripteditorws.h" #include "llagent.h" +#include "llagentcamera.h" #include "llappviewer.h" #include "llchat.h" #include "lldate.h" @@ -61,6 +62,7 @@ #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llviewermenu.h" #include "llviewertexteditor.h" #include "llvoinventorylistener.h" #include "roles_constants.h" @@ -166,6 +168,46 @@ LLScriptEditorWSServer::LLScriptEditorWSServer(const std::string& name, U16 port { LL_INFOS("ScriptEditorWS") << "Created JSON-RPC script editor server: " << name << " on port " << port << LL_ENDL; + + registerCommand({ "viewer.teleport", "Teleport agent to an in-world object" }, + [](U32, const LLSD& p) -> LLSD + { + LLUUID object_id = p["object_id"].asUUID(); + if (object_id.isNull()) + throw LLJSONRPCConnection::InvalidParams("object_id is required"); + + LLViewerObject* object = gObjectList.findObject(object_id); + if (!object) + throw LLJSONRPCConnection::InvalidParams("object_id not found"); + + LLVector3d global_pos = object->getPositionGlobal(); + gAgent.teleportViaLocation(global_pos); + + LLSD response; + response["success"] = true; + return response; + }); + + registerCommand({ "viewer.camera.focus", "Zoom camera to an in-world object (same behavior as context menu Zoom In)" }, + [](U32, const LLSD& p) -> LLSD + { + LLUUID object_id = p["object_id"].asUUID(); + if (object_id.isNull()) + throw LLJSONRPCConnection::InvalidParams("object_id is required"); + + if (!handle_zoom_to_object(object_id)) + { + LLSD response; + response["success"] = false; + response["error_code"] = WSCommandError::ExecutionError; + response["message"] = "Object not found or not reachable"; + return response; + } + + LLSD response; + response["success"] = true; + return response; + }); } LLScriptEditorWSServer::ptr_t LLScriptEditorWSServer::getServer() @@ -623,6 +665,18 @@ void LLScriptEditorWSServer::setupConnectionMethods(LLJSONRPCConnection::ptr_t c { return s.handleObjectItemModify(connection_id, params); })); + + script_connection->registerAsyncMethod("command.execute", + bindHandler([connection_id](LLScriptEditorWSServer& s, auto&, auto&, const LLSD& params) + { + return s.handleCommandExecute(connection_id, params); + })); + + script_connection->registerMethod("command.list", + bindHandler([](LLScriptEditorWSServer& s, auto&, auto&, auto&) + { + return s.handleCommandList(); + })); } } @@ -854,6 +908,79 @@ LLSD LLScriptEditorWSServer::handleObjectItemModify(U32 connection_id, const LLS return response; } +void LLScriptEditorWSServer::registerCommand(const WSCommandInfo& info, WSCommandHandler handler) +{ + mCommandRegistry.emplace(info.command, std::make_pair(info, std::move(handler))); +} + +bool LLScriptEditorWSConnection::hasFeature(const std::string& feature) const +{ + return mFeatures.count(feature) > 0; +} + +LLSD LLScriptEditorWSServer::handleCommandExecute(U32 connection_id, const LLSD& params) +{ + const std::string command = params["command"].asString(); + if (command.empty()) + { + throw LLJSONRPCConnection::InvalidParams("command is required"); + } + + auto it = mCommandRegistry.find(command); + if (it == mCommandRegistry.end()) + { + LLSD response; + response["success"] = false; + response["error_code"] = WSCommandError::UnknownCommand; + response["message"] = "Unknown command: " + command; + return response; + } + + return it->second.second(connection_id, params["params"]); +} + +LLSD LLScriptEditorWSServer::handleCommandList() +{ + LLSD commands(LLSD::emptyArray()); + for (const auto& [name, entry] : mCommandRegistry) + { + LLSD info; + info["command"] = entry.first.command; + info["description"] = entry.first.description; + commands.append(info); + } + LLSD response; + response["commands"] = commands; + return response; +} + +void LLScriptEditorWSServer::sendCommandExecute( + U32 connection_id, const std::string& command, const LLSD& params) +{ + auto it = mActiveConnections.find(connection_id); + if (it == mActiveConnections.end()) + { + return; + } + + auto connection = it->second.lock(); + if (!connection || !connection->hasFeature("commands")) + { + return; + } + + LLSD call_params; + call_params["command"] = command; + call_params["params"] = params; + + connection->call("command.execute", call_params, + [command](const LLSD& result, const LLSD& error) + { + LL_WARNS_IF(!error.isUndefined() || !result["success"].asBoolean(), "WSCommand") + << "command.execute failed for " << command << LL_ENDL; + }); +} + void LLScriptEditorWSServer::broadcastLanguageChange() { LLUUID syntax_id = LLSyntaxDefCache::instance().getSyntaxID(); @@ -2300,6 +2427,7 @@ void LLScriptEditorWSConnection::onOpen() features["live_sync"] = true; features["compilation"] = true; features["syntax_cache"] = true; + features["commands"] = true; handshake["features"] = features; wptr_t that = weak_from_this(); |
