From 0cc0db81afec26842ea9887aa50afb072d13914c Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 25 Feb 2025 06:43:52 +0200 Subject: #3422 Better handling of Lua syntax --- indra/newview/llsyntaxid.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'indra/newview/llsyntaxid.cpp') diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index 5114ee3672..1f8766eea2 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -40,7 +40,8 @@ //----------------------------------------------------------------------------- const std::string SYNTAX_ID_CAPABILITY_NAME = "LSLSyntax"; const std::string SYNTAX_ID_SIMULATOR_FEATURE = "LSLSyntaxId"; -const std::string FILENAME_DEFAULT = "keywords_lsl_default.xml"; +const std::string FILENAME_DEFAULT_LSL = "keywords_lsl_default.xml"; +const std::string FILENAME_DEFAULT_LUA = "keywords_lua_default.xml"; /** * @brief LLSyntaxIdLSL constructor @@ -60,7 +61,7 @@ LLSyntaxIdLSL::LLSyntaxIdLSL() void LLSyntaxIdLSL::buildFullFileSpec() { ELLPath path = mSyntaxId.isNull() ? LL_PATH_APP_SETTINGS : LL_PATH_CACHE; - const std::string filename = mSyntaxId.isNull() ? FILENAME_DEFAULT : "keywords_lsl_" + mSyntaxId.asString() + ".llsd.xml"; + const std::string filename = mSyntaxId.isNull() ? FILENAME_DEFAULT_LSL : "keywords_lsl_" + mSyntaxId.asString() + ".llsd.xml"; mFullFileSpec = gDirUtilp->getExpandedFilename(path, filename); } @@ -325,3 +326,38 @@ boost::signals2::connection LLSyntaxIdLSL::addSyntaxIDCallback(const syntax_id_c { return mSyntaxIDChangedSignal.connect(cb); } + + + +//----------------------------------------------------------------------------- +// LLSyntaxLua +//----------------------------------------------------------------------------- +LLSyntaxLua::LLSyntaxLua() + : mKeywordsXml(LLSD()) + , mInitialized(false) +{ +} + +void LLSyntaxLua::initialize() +{ + if (mInitialized) return; + + loadDefaultKeywordsIntoLLSD(); + + mInitialized = true; +} + +void LLSyntaxLua::loadDefaultKeywordsIntoLLSD() +{ + std::string fullFileSpec = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, FILENAME_DEFAULT_LUA); + llifstream file(fullFileSpec.c_str()); + + if (file.good()) + { + LLSD content; + if (LLSDSerialize::fromXML(content, file) != LLSDParser::PARSE_FAILURE) + { + mKeywordsXml = content; + } + } +} -- cgit v1.3 From 684af8426b36f9ad4c2324ae0c5b4dc62f840079 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 17 Sep 2025 13:14:23 -0700 Subject: initial Lua types files, and switch websocket server to use a single connection for all scripts. --- indra/llcommon/llstl.h | 204 +++++++++++++++++ indra/llcorehttp/llwebsocketmgr.cpp | 31 +++ indra/llcorehttp/llwebsocketmgr.h | 62 ++---- indra/newview/CMakeLists.txt | 2 + indra/newview/llpreviewscript.cpp | 48 ++-- indra/newview/llpreviewscript.h | 11 +- indra/newview/llscripteditorws.cpp | 423 +++++++++++++++++++++++------------- indra/newview/llscripteditorws.h | 141 ++++++------ indra/newview/llsyntaxid.cpp | 17 +- indra/newview/llsyntaxid.h | 22 +- 10 files changed, 650 insertions(+), 311 deletions(-) (limited to 'indra/newview/llsyntaxid.cpp') diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 7d41c42ba7..0088eeec67 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef LL_LINUX // For strcmp @@ -709,5 +710,208 @@ struct ll_template_cast_impl \ } \ } +//----------------------------------------------- +namespace LL +{ + /** + * @brief A range adapter that provides filtered iteration over a container. + * + * filter_range creates a filtered view of an iterator range using a predicate function. + * Only elements that satisfy the predicate will be accessible when iterating through + * the range. This is useful for processing subsets of containers without copying data. + * + * The class uses boost::filter_iterator internally to provide the filtering functionality. + * + * @tparam Predicate A callable object (function, functor, lambda) that takes an element + * from the iterator range and returns true if the element should be + * included in the filtered range. + * @tparam Iterator The iterator type for the underlying container/range. + * + * Example usage: + * @code + * std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * + * // Create a predicate to filter even numbers + * auto is_even = [](int n) { return n % 2 == 0; }; + * + * // Create filtered range using make_filter helper + * auto even_range = LL::make_filter(is_even, numbers.begin(), numbers.end()); + * + * // Iterate through only even numbers + * for (auto value : even_range) { + * std::cout << value << " "; // Prints: 2 4 6 8 10 + * } + * + * // Or manually construct the filter_range + * LL::filter_range::iterator> + * manual_range(is_even, numbers.begin(), numbers.end()); + * @endcode + * + * @note This class provides a lightweight view over the original data. + * No copying of elements occurs, making it efficient for large containers. + * @note The predicate is applied during iteration, so complex predicates may + * impact performance for frequently-accessed ranges. + * @note The underlying container must remain valid for the lifetime of the filter_range. + * + * @see make_filter() for a convenient factory function + * @see boost::filter_iterator for the underlying implementation details + */ + template + class filter_range + { + public: + /// The filtered iterator type - combines predicate with base iterator + using filter_iter = boost::filter_iterator; + + /// Value type of the filtered elements + using value_type = typename std::iterator_traits::value_type; + + /// Iterator type for range-based for loops and STL algorithms + using iterator = filter_iter; + using const_iterator = filter_iter; + + /** + * @brief Constructs a filter_range with the given predicate and iterator range. + * + * @param pred The predicate function/functor to filter elements. + * Must be callable with signature: bool(const value_type&) + * @param begin Iterator to the beginning of the range to filter + * @param end Iterator to the end of the range to filter + * + * @pre begin and end must form a valid iterator range + * @pre pred must be a valid callable that can be invoked with elements from [begin, end) + */ + filter_range(Predicate pred, Iterator begin, Iterator end) + : begin_(pred, begin, end), end_(pred, end, end) {} + + /** + * @brief Returns an iterator to the first element that satisfies the predicate. + * + * @return filter_iter Iterator pointing to the first filtered element, + * or equal to end() if no elements satisfy the predicate. + */ + filter_iter begin() const { return begin_; } + + /** + * @brief Returns an iterator representing the end of the filtered range. + * + * @return filter_iter Past-the-end iterator for the filtered range. + */ + filter_iter end() const { return end_; } + + /** + * @brief Checks if the filtered range is empty. + * + * @return true if no elements in the range satisfy the predicate, false otherwise. + * + * @note This operation has O(1) complexity as it only compares iterators. + */ + bool empty() const { return begin_ == end_; } + + private: + filter_iter begin_; ///< Iterator to first element satisfying predicate + filter_iter end_; ///< Past-the-end iterator for the filtered range + }; + + /** + * @brief Factory function to create a filter_range with automatic template deduction. + * + * This convenience function eliminates the need to explicitly specify template parameters + * when creating a filter_range. The template parameters are automatically deduced from + * the function arguments. + * + * @tparam Predicate Automatically deduced predicate type + * @tparam Iterator Automatically deduced iterator type + * + * @param pred Predicate function/functor for filtering elements + * @param begin Iterator to the beginning of the range + * @param end Iterator to the end of the range + * + * @return filter_range A filter_range object configured with + * the provided predicate and range + * + * Example usage: + * @code + * std::vector words = {"hello", "world", "test", "example"}; + * + * // Filter strings longer than 4 characters + * auto long_words = LL::make_filter( + * [](const std::string& s) { return s.length() > 4; }, + * words.begin(), + * words.end() + * ); + * + * // Use with range-based for loop + * for (const auto& word : long_words) { + * std::cout << word << std::endl; // Prints: hello, world, example + * } + * + * // Use with STL algorithms + * auto count = std::distance(long_words.begin(), long_words.end()); + * std::cout << "Found " << count << " long words." << std::endl; + * @endcode + * + * @note This function is preferred over direct construction of filter_range + * for most use cases due to automatic template parameter deduction. + */ + template + filter_range make_filter(Predicate pred, Iterator begin, Iterator end) + { + return filter_range(pred, begin, end); + } + + /** + * @brief Create a filter_range over an entire container with automatic template deduction. + * + * This convenience function creates a filtered view over an entire container without + * requiring explicit begin() and end() calls. It automatically handles both const and + * non-const containers, preserving constness in the resulting iterator types. + * + * @tparam Predicate Automatically deduced predicate type + * @tparam Container Automatically deduced container type (const or non-const) + * + * @param pred Predicate function/functor for filtering elements + * @param container The container to filter (can be const or non-const) + * + * @return filter_range with appropriate iterator type for the container + * + * Example usage: + * @code + * // Non-const container + * std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * auto evens = LL::make_filter([](int n) { return n % 2 == 0; }, numbers); + * + * // Const container + * const std::list words = {"cat", "elephant", "dog", "hippopotamus"}; + * auto long_words = LL::make_filter([](const std::string& s) { return s.size() > 3; }, words); + * + * // Works with any container that supports begin()/end() + * std::set values = {1.1, 2.2, 3.3, 4.4, 5.5}; + * auto large_values = LL::make_filter([](double d) { return d > 3.0; }, values); + * + * // Use with range-based for loops + * for (const auto& word : long_words) { + * std::cout << word << " "; // Prints: elephant hippopotamus + * } + * + * // Chain with STL algorithms + * auto even_count = std::distance(evens.begin(), evens.end()); + * std::cout << "Found " << even_count << " even numbers." << std::endl; + * @endcode + * + * @note This overload automatically calls begin() and end() on the container, + * making it more convenient than the iterator-based version. + * @note The container must remain valid for the lifetime of the returned filter_range. + * @note Constness of the container is preserved in the iterator type. + */ + template + filter_range()))> + make_filter(Predicate pred, Container&& container) + { + return filter_range()))>( + pred, std::begin(container), std::end(container)); + } + +} // namespace LL #endif // LL_LLSTL_H diff --git a/indra/llcorehttp/llwebsocketmgr.cpp b/indra/llcorehttp/llwebsocketmgr.cpp index d44d5d877d..09eb728500 100644 --- a/indra/llcorehttp/llwebsocketmgr.cpp +++ b/indra/llcorehttp/llwebsocketmgr.cpp @@ -485,6 +485,7 @@ bool LLWebsocketMgr::WSServer::start() LL_INFOS("WebSocket") << "WebSocket server thread exiting for: " << mServerName << LL_ENDL; }); + onStarted(); LL_INFOS("WebSocket") << "Started WebSocket server thread: " << mServerName << LL_ENDL; return true; } @@ -517,6 +518,7 @@ void LLWebsocketMgr::WSServer::stop() mServerThread.join(); LL_INFOS("WebSocket") << "WebSocket server thread joined for: " << mServerName << LL_ENDL; } + onStopped(); } bool LLWebsocketMgr::WSServer::isRunning() const @@ -596,6 +598,20 @@ LLWebsocketMgr::WSConnection::ptr_t LLWebsocketMgr::WSServer::getConnection(cons return nullptr; } +LLWebsocketMgr::connection_state_t LLWebsocketMgr::WSServer::getConnectionState(const connection_h& handle) const +{ + websocketpp::lib::error_code ec; + auto con = mImpl->mServer.get_con_from_hdl(handle, ec); + if (ec) + { + LL_WARNS("WebSocket") << mServerName << " failed to get connection state: " << ec.message() << LL_ENDL; + websocketpp::session::state::value state = websocketpp::session::state::closed; + return connection_closed; + } + return static_cast(con->get_state()); +} + + void LLWebsocketMgr::WSServer::handleOpenConnection(const connection_h& handle) { WSConnection::ptr_t connection; @@ -709,3 +725,18 @@ void LLWebsocketMgr::WSConnection::closeConnection(U16 code, const std::string& LL_WARNS("WebSocket") << "Failed to close connection through server" << LL_ENDL; } } + +bool LLWebsocketMgr::WSConnection::isConnected() const +{ + if (mOwningServer.expired()) + { + return false; + } + + LLWebsocketMgr::WSServer::ptr_t server = mOwningServer.lock(); + if (!server) + { + return false; + } + return server->getConnectionState(mConnectionHandle) == connection_open; +} diff --git a/indra/llcorehttp/llwebsocketmgr.h b/indra/llcorehttp/llwebsocketmgr.h index 570c8ad6cd..4165b3cecc 100644 --- a/indra/llcorehttp/llwebsocketmgr.h +++ b/indra/llcorehttp/llwebsocketmgr.h @@ -64,6 +64,14 @@ public: using connection_h = websocketpp::connection_hdl; class WSServer; + enum connection_state_t + { // must map to websocketpp::session::state + connection_connecting = 0, + connection_open = 1, + connection_closing = 2, + connection_closed = 3 + }; + class WSConnection { friend class LLWebsocketMgr; @@ -84,8 +92,6 @@ public: virtual ~WSConnection() = default; /** - * @brief Called when the connection is opened - * * Override this method in derived classes to handle connection establishment. * This is called after the WebSocket handshake is complete and the connection * is ready to send/receive messages. @@ -93,8 +99,6 @@ public: virtual void onOpen() {} /** - * @brief Called when the connection is closed - * * Override this method in derived classes to handle connection closure. * This is called when the connection has been terminated, either normally * or due to an error condition. @@ -107,27 +111,6 @@ public: * * Override this method in derived classes to handle incoming messages. * Currently only text messages are supported. - * - * @code - * class MyConnection : public LLWebsocketMgr::WSConnection - * { - * public: - * void onMessage(const std::string& message) override - * { - * // Parse and handle the message - * if (message == "ping") { - * sendMessage("pong"); - * } - * // Process JSON messages - * try { - * LLSD data = LLSDSerialize::fromJSON(message); - * handleStructuredMessage(data); - * } catch (...) { - * LL_WARNS("MyConnection") << "Invalid JSON received" << LL_ENDL; - * } - * } - * }; - * @endcode */ virtual void onMessage(const std::string& message) {} @@ -138,17 +121,6 @@ public: * * Sends a text message to the remote endpoint. The message is queued * asynchronously and may not be sent immediately. - * - * @code - * // Send a simple text message - * connection->sendMessage("Hello, client!"); - * - * // Send JSON data - * LLSD response; - * response["status"] = "ok"; - * response["data"] = "some data"; - * connection->sendMessage(LLSDSerialize::toJSON(response)); - * @endcode */ bool sendMessage(const std::string& message) const; bool sendMessage(const boost::json::value& json) const; @@ -172,22 +144,13 @@ public: * - 1008: Policy violation * - 1009: Message too big * - * @code - * // Normal closure - * connection->closeConnection(); - * - * // Close with specific reason - * connection->closeConnection(1000, "Session ended"); - * - * // Close due to policy violation - * connection->closeConnection(1008, "Authentication failed"); - * @endcode - * * @note After calling this method, no further messages should be sent * @note The onClose() callback will be invoked when the close handshake completes */ void closeConnection(U16 code = 1000, const std::string& reason = std::string()); + bool isConnected() const; + protected: connection_h mConnectionHandle; std::weak_ptr mOwningServer; // Back-reference to the server this connection belongs to @@ -260,6 +223,9 @@ public: WSServer(std::string_view name, U16 port, bool local_only = true); virtual ~WSServer(); + virtual void onStarted() {} + virtual void onStopped() {} + virtual void onConnectionOpened(const WSConnection::ptr_t& connection) { } virtual void onConnectionClosed(const WSConnection::ptr_t& connection) { } @@ -273,6 +239,8 @@ public: void broadcastMessage(const std::string& message); virtual bool update() { return true; } + connection_state_t getConnectionState(const connection_h& handle) const; + protected: virtual WSConnection::ptr_t connectionFactory(WSServer::ptr_t server, connection_h handle); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d1527ef578..6c7b4fef81 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1663,6 +1663,7 @@ set(viewer_APPSETTINGS_FILES app_settings/ignorable_dialogs.xml app_settings/key_bindings.xml app_settings/keywords_lsl_default.xml + app_settings/keywords_lua_default.xml app_settings/logcontrol.xml app_settings/settings.xml app_settings/settings_crash_behavior.xml @@ -1671,6 +1672,7 @@ set(viewer_APPSETTINGS_FILES app_settings/std_bump.ini app_settings/toolbars.xml app_settings/trees.xml + app_settings/types_lua_default.llsd app_settings/viewerart.xml app_settings/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 3ab2e747ea..f17b2aeed1 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1553,6 +1553,11 @@ LLScriptEdContainer::~LLScriptEdContainer() delete mLiveLogFile; mLiveLogFile = nullptr; + + if (!mWebSocketServer.expired()) + { + unsubscribeScript(); + } } std::string LLScriptEdContainer::getTmpFileName(const std::string& script_name) const @@ -1675,44 +1680,45 @@ void LLScriptEdContainer::startWebsocketServer() U16 server_port(LLScriptEditorWSServer::DEFAULT_SERVER_PORT); bool server_localhost(true); + // Attempt to find an existing server LLWebsocketMgr& wsmgr = LLWebsocketMgr::instance(); LLScriptEditorWSServer::ptr_t server = std::static_pointer_cast(wsmgr.findServerByName(server_name)); if (!server) - { + { // We couldn't find one, so create it server = std::make_shared(server_name, server_port, server_localhost); wsmgr.addServer(server); - wsmgr.startServer(server_name); + } + + bool is_running = server->isRunning(); + if (!is_running) + { // Server isn't running, so start it + is_running = wsmgr.startServer(server_name); + } + + if (!is_running && !server->isRunning()) + { // Failed to start the server + LL_WARNS() << "Failed to start script editor websocket server" << LL_ENDL; + return; } std::string script_id_hash_str(getUniqueHash()); - server->associateEditor(getHandle(), script_id_hash_str); + server->subscribeScriptEditor(getHandle(), script_id_hash_str); + mWebSocketServer = server; } } -void LLScriptEdContainer::attachToWebSocket(const std::shared_ptr& connection) +void LLScriptEdContainer::unsubscribeScript() { - mWebSocket = connection; -} - -void LLScriptEdContainer::detachFromWebSocket(bool send_disconnect) -{ - if (mWebSocket) + auto server = mWebSocketServer.lock(); + if (server) { - if (send_disconnect) - { - // TODO: - mWebSocket->sendDisconnect(LLScriptEditorWSConnection::REASON_EDITOR_CLOSED); - mWebSocket->closeConnection(); - } - mWebSocket.reset(); + std::string script_id_hash_str(getUniqueHash()); + server->sendUnsubscribeScriptEditor(script_id_hash_str); + server->unsubscribeEditor(script_id_hash_str); } } -void LLScriptEdContainer::cleanupWebSocket() -{ - mWebSocket.reset(); -} /// --------------------------------------------------------------------------- /// LLPreviewLSL diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 72d52a115e..8d53c8899c 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -54,7 +54,7 @@ class LLScriptEdContainer; class LLFloaterGotoLine; class LLFloaterExperienceProfile; class LLScriptMovedObserver; -class LLScriptEditorWSConnection; +class LLScriptEditorWSServer; class LLLiveLSLFile : public LLLiveFile { @@ -105,6 +105,7 @@ public: void initMenu(); void processKeywords(); void processKeywords(bool luau_language); + LLKeywords& getKeywords() { return mEditor->getKeywords(); } void draw() override; bool postBuild() override; @@ -221,9 +222,9 @@ public: bool handleKeyHere(KEY key, MASK mask); void startWebsocketServer(); - void attachToWebSocket(const std::shared_ptr& connection); - void detachFromWebSocket(bool send_disconnect); - void cleanupWebSocket(); + void unsubscribeScript(); + + LLScriptEdCore* getScriptEdCore() const { return mScriptEd; } protected: std::string getTmpFileName(const std::string& script_name) const; @@ -238,7 +239,7 @@ protected: LLLiveLSLFile* mLiveFile = nullptr; LLLiveLSLFile* mLiveLogFile = nullptr; - std::shared_ptr mWebSocket; + std::weak_ptr mWebSocketServer; }; // Used to view and edit an LSL script from your inventory. diff --git a/indra/newview/llscripteditorws.cpp b/indra/newview/llscripteditorws.cpp index 9863130aea..cb67880455 100644 --- a/indra/newview/llscripteditorws.cpp +++ b/indra/newview/llscripteditorws.cpp @@ -24,24 +24,6 @@ * $/LicenseInfo$ */ -/** - * This implementation provides JSON-RPC 2.0 WebSocket communication between - * the Second Life viewer and external script editors. It uses the standard - * JSON-RPC 2.0 protocol without pre-defined script-specific methods, - * allowing for flexible integration approaches. - * - * ## JSON-RPC Integration - * - * The connection provides a clean JSON-RPC 2.0 interface that can be - * extended with script-specific functionality as needed: - * - * ### Server-to-Client (Viewer to Editor): - * - `session.handshake`: Welcome message on connection - * - `session.disconnect`: Notify editor of disconnection - * - * ### Notifications (no response expected): - */ - #include "llviewerprecompiledheaders.h" #include "llscripteditorws.h" #include "llpreviewscript.h" @@ -51,6 +33,7 @@ #include "llerror.h" #include "lluuid.h" #include "llversioninfo.h" +#include "llagent.h" //======================================================================== LLScriptEditorWSServer::LLScriptEditorWSServer(const std::string& name, U16 port, bool local_only) @@ -64,7 +47,7 @@ LLWebsocketMgr::WSConnection::ptr_t LLScriptEditorWSServer::connectionFactory(LL LLWebsocketMgr::connection_h handle) { auto connection = std::make_shared(server, handle); - mActiveConnections.insert(connection); + mActiveConnections[connection->getConnectionID()] = connection; // Call setupConnectionMethods to register any global methods setupConnectionMethods(connection); @@ -72,6 +55,29 @@ LLWebsocketMgr::WSConnection::ptr_t LLScriptEditorWSServer::connectionFactory(LL return connection; } +void LLScriptEditorWSServer::onStarted() +{ + LLSyntaxIdLSL& syntax_id_mgr = LLSyntaxIdLSL::instance(); + wptr_t that(std::static_pointer_cast(shared_from_this())); + + mLastSyntaxId = syntax_id_mgr.getSyntaxID(); + mLanguageChangeSignal = syntax_id_mgr.addSyntaxIDCallback( + [that]() + { + auto server = that.lock(); + if (server && server->isRunning()) + { + server->broadcastLangugeChange(); + } + }); +} + +void LLScriptEditorWSServer::onStopped() +{ + mLanguageChangeSignal.disconnect(); + mLastSyntaxId.setNull(); +} + void LLScriptEditorWSServer::onConnectionOpened(const LLWebsocketMgr::WSConnection::ptr_t& connection) { // Call parent class to handle JSON-RPC setup and standard methods @@ -92,35 +98,102 @@ void LLScriptEditorWSServer::onConnectionClosed(const LLWebsocketMgr::WSConnecti auto script_connection = std::dynamic_pointer_cast(connection); if (script_connection) { - mActiveConnections.erase(script_connection); + U32 connection_id = script_connection->getConnectionID(); + unsubscribeConnection(connection_id); + mActiveConnections.erase(connection_id); - LL_INFOS("ScriptEditorWS") << "Removed connection from active connections. Total: " + LL_DEBUGS("ScriptEditorWS") << "Removed connection from active connections. Total: " << mActiveConnections.size() << LL_ENDL; // TODO: When connections reach 0, stop the server aftera a timeout. } } -bool LLScriptEditorWSServer::associateEditor(const LLHandle& editor_handle, const std::string& script_id) +bool LLScriptEditorWSServer::subscribeScriptEditor(const LLHandle& editor_handle, const std::string &script_id) { if (!editor_handle.isDead()) { - mScriptEditors[script_id] = editor_handle; + auto it = mSubscriptions.find(script_id); + if (it == mSubscriptions.end()) + { // Don't readd if already subscribed + mSubscriptions.emplace(script_id, EditorSubscription{ editor_handle, LLScriptEditorWSConnection::wptr_t() }); + return false; + } + else + { // Update existing subscription with new editor handle + it->second.mEditorHandle = editor_handle; + } return true; } return false; } -void LLScriptEditorWSServer::dissociateEditor(const std::string& script_id) +void LLScriptEditorWSServer::unsubscribeEditor(const std::string &script_id) +{ + auto it = mSubscriptions.find(script_id); + if (it != mSubscriptions.end()) + { + mSubscriptions.erase(it); + } +} + +void LLScriptEditorWSServer::unsubscribeConnection(U32 connection_id) +{ + for (auto it = mSubscriptions.begin(); it != mSubscriptions.end(); ) + { + if (it->second.mConnectionID == connection_id) + { + LL_DEBUGS("ScriptEditorWS") << "Unsubscribing script " << it->first + << " from connection ID " << connection_id << LL_ENDL; + it = mSubscriptions.erase(it); + } + else + { + ++it; + } + } +} + +LLScriptEditorWSServer::SubscriptionError_t LLScriptEditorWSServer::updateScriptSubscription(const std::string &script_id, U32 connection_id) { - mScriptEditors.erase(script_id); + auto it = mSubscriptions.find(script_id); + if (it != mSubscriptions.end()) + { + if (it->second.mEditorHandle.isDead()) + { + unsubscribeEditor(script_id); + return SUBSCRIPTION_INVALID_EDITOR; + } + + auto con_it = mActiveConnections.find(connection_id); + if (con_it == mActiveConnections.end()) + { + return SUBSCRIPTION_INTERNAL_ERROR; + } + + if ((it->second.mConnectionID != 0) && !it->second.mConnection.expired() + && it->second.mConnection.lock()->isConnected()) + { + LL_WARNS("ScriptEditorWS") << "Script " << script_id << " is already subscribed on connection ID " << it->second.mConnectionID + << ", cannot subscribe again on connection ID " << connection_id << LL_ENDL; + // In the future we may want to support multiple connections per script. + // That would imply it was open in multiple editors. + return SUBSCRIPTION_ALREADY_SUBSCRIBED; + } + + it->second.mConnectionID = connection_id; + it->second.mConnection = con_it->second; + return SUBSCRIPTION_SUCCESS; + } + return SUBSCRIPTION_INVALID_SUBSCRIPTION; } + LLHandle LLScriptEditorWSServer::findEditorForScript(const std::string& script_id) const { - auto it = mScriptEditors.find(script_id); - if (it != mScriptEditors.end()) + auto it = mSubscriptions.find(script_id); + if (it != mSubscriptions.end()) { - return it->second; + return it->second.mEditorHandle; } return LLHandle(); } @@ -135,9 +208,9 @@ std::shared_ptr LLScriptEditorWSServer::findConnecti std::set LLScriptEditorWSServer::getActiveScripts() const { std::set active_scripts; - for (const auto& [script_id, editor_handle] : mScriptEditors) + for (const auto& [script_id, subinfo] : mSubscriptions) { - if (!editor_handle.isDead()) + if (!subinfo.mEditorHandle.isDead()) { active_scripts.insert(script_id); } @@ -145,69 +218,182 @@ std::set LLScriptEditorWSServer::getActiveScripts() const return active_scripts; } -void LLScriptEditorWSServer::broadcastScriptUpdate(const std::string& script_id, const std::string& content, const LLSD& metadata) +void LLScriptEditorWSServer::setupConnectionMethods(LLJSONRPCConnection::ptr_t connection) { - LL_DEBUGS("ScriptEditorWS") << "Broadcasting script update for script: " << script_id << LL_ENDL; + // Call parent class to register global JSON-RPC methods + LLJSONRPCServer::setupConnectionMethods(connection); - LLSD params; - params["script_id"] = script_id; - params["content"] = content; - params["timestamp"] = LLDate::now().asString(); + // Cast to our specific connection type to access script editor functionality + auto script_connection = std::dynamic_pointer_cast(connection); + if (script_connection) + { + LL_DEBUGS("ScriptEditorWS") << "Setting up script editor connection methods" << LL_ENDL; + wptr_t that(std::static_pointer_cast(shared_from_this())); + + U32 connection_id = script_connection->getConnectionID(); + + script_connection->registerMethod("language.syntax.id", + [that](const std::string&, const LLSD&, const LLSD&) -> LLSD + { + auto server = that.lock(); + if (server) + { + return server->handleLanguageIdRequest(); + } + return LLSD(); + }); + script_connection->registerMethod("language.syntax", + [that](const std::string&, const LLSD&, const LLSD& params) + { + auto server = that.lock(); + if (server) + { + return server->handleSyntaxRequest(params); + } + return LLSD(); + }); + script_connection->registerMethod("script.subscribe", + [that, connection_id](const std::string&, const LLSD&, const LLSD& params) -> LLSD + { + auto server = that.lock(); + if (server) + { + return server->handleScriptSubscribe(connection_id, params); + } + return LLSD(); + }); + script_connection->registerMethod("script.unsubscribe", [](const std::string&, const LLSD&, const LLSD& params) -> LLSD + { // this is a notification, no response expected + return LLSD(); + }); + // script_connection->registerMethod("language.syntax", ) + } +} + +void LLScriptEditorWSServer::broadcastLangugeChange() +{ + LLUUID syntax_id = LLSyntaxIdLSL::instance().getSyntaxID(); - if (!metadata.isUndefined()) + if (syntax_id != mLastSyntaxId) { - params["metadata"] = metadata; + mLastSyntaxId = syntax_id; + LLSD params; + params["id"] = syntax_id; + + if (isRunning()) + { + broadcastNotification("language.syntax.change", params); + } } +} - // Send to all connected editors as a notification - broadcastNotification("script.update", params); +LLSD LLScriptEditorWSServer::handleLanguageIdRequest() const +{ + LLSD response; + + response["id"] = mLastSyntaxId; + return response; } -void LLScriptEditorWSServer::broadcastCompilationResult(const std::string& script_id, bool success, const LLSD& errors) +LLSD LLScriptEditorWSServer::handleSyntaxRequest(const LLSD& params) const { - LL_DEBUGS("ScriptEditorWS") << "Broadcasting compilation result for script: " << script_id - << " (success: " << success << ")" << LL_ENDL; + LLSD response(LLSD::emptyMap()); + std::string category = params["kind"].asString(); - LLSD params; - params["script_id"] = script_id; - params["success"] = success; - params["timestamp"] = LLDate::now().asString(); + response["id"] = mLastSyntaxId; - if (!errors.isUndefined() && errors.isArray()) + if (category == "types.luau") { - params["errors"] = errors; + response["types"] = LLSyntaxLua::instance().getTypesXML(); } + else + { + LLSD syntax = LLSyntaxIdLSL::instance().getKeywordsXML(); + + // TODO: support language definitions and additional modules. - // Send to all connected editors as a notification - broadcastNotification("compilation.result", params); + if (syntax.has(category)) + { + response[category] = syntax[category]; + } + } + return response; } -void LLScriptEditorWSServer::setupConnectionMethods(LLJSONRPCConnection::ptr_t connection) +LLSD LLScriptEditorWSServer::handleScriptSubscribe(U32 connection_id, const LLSD& params) { - // Call parent class to register global JSON-RPC methods - LLJSONRPCServer::setupConnectionMethods(connection); + LLSD response(LLSD::emptyMap()); - // Cast to our specific connection type to access script editor functionality - auto script_connection = std::dynamic_pointer_cast(connection); - if (script_connection) + std::string script_id = params["script_id"].asString(); + std::string script_name = params["script_name"].asString(); + std::string language = params["script_language"].asString(); + + SubscriptionError_t result = updateScriptSubscription(script_id, connection_id); + + response["script_id"] = script_id; + response["success"] = (result == SUBSCRIPTION_SUCCESS); + response["status"] = result; + + LL_WARNS_IF(result != SUBSCRIPTION_SUCCESS, "ScriptEditorWS") + << "Script connect request for script " << script_id << " failed with status " << result << LL_ENDL; + switch (result) { - LL_INFOS("ScriptEditorWS") << "Setting up script editor connection methods" << LL_ENDL; + case SUBSCRIPTION_SUCCESS: + response["message"] = "OK"; + break; + case SUBSCRIPTION_INVALID_EDITOR: + response["message"] = "Invalid editor handle"; + break; + case SUBSCRIPTION_INVALID_SUBSCRIPTION: + response["message"] = "No subscription found for script"; + break; + case SUBSCRIPTION_ALREADY_SUBSCRIBED: + response["message"] = "Script already subscribed"; + break; + case SUBSCRIPTION_INTERNAL_ERROR: + response["message"] = "Internal server error"; + break; + } + + if (result == SUBSCRIPTION_SUCCESS) + { + //TODO: Build an info block for the subscribed script. + //buildScriptSubscriptionInfo(result); + } - // Here derived classes could add script-specific method registrations - // For now, the base LLScriptEditorWSConnection doesn't register any specific methods - // but this provides a hook for future customization + return response; +} + +LLSD LLScriptEditorWSServer::handleScriptUnsubscribe(U32 connection_id, const LLSD& params) +{ + std::string script_id = params["script_id"].asString(); - // Example of how custom methods could be registered: - // script_connection->registerMethod("script.custom", handler); + auto it = mSubscriptions.find(script_id); + if (it != mSubscriptions.end() && (it->second.mConnectionID == connection_id)) + { + unsubscribeEditor(script_id); } + return LLSD(); } -//======================================================================== -LLScriptEdContainer* LLScriptEditorWSConnection::getEditor() const +void LLScriptEditorWSServer::sendUnsubscribeScriptEditor(const std::string& script_id) { - return mEditorPanel.isDead() ? nullptr : dynamic_cast(mEditorPanel.get()); + auto it = mSubscriptions.find(script_id); + if (it != mSubscriptions.end()) + { + auto connection = it->second.mConnection.lock(); + if (connection) + { + LLSD params; + params["script_id"] = script_id; + connection->notify("script.unsubscribe", params); + } + } } +//======================================================================== +U32 LLScriptEditorWSConnection::sNextConnectionID = 1; + std::shared_ptr LLScriptEditorWSConnection::getServer() const { return std::static_pointer_cast(mOwningServer.lock()); @@ -220,20 +406,17 @@ void LLScriptEditorWSConnection::onOpen() LL_INFOS("ScriptEditorWS") << "Script editor JSON-RPC connection opened" << LL_ENDL; - // Generate unique editor session ID - mEditorId = LLUUID::generateNewID().asString(); - mEditorReady = false; - - LL_INFOS("ScriptEditorWS") << "Initialized editor session: " << mEditorId << LL_ENDL; - - // Build hello data according to the protocol specification + // Build hello data LLSD handshake; handshake["server_version"] = "1.0.0"; handshake["protocol_version"] = "1.0"; handshake["viewer_name"] = LLVersionInfo::instance().getChannel(); handshake["viewer_version"] = LLVersionInfo::instance().getVersion(); - // Supported languages array + handshake["agent_id"] = gAgent.getID(); + + // handshake["challenge"] = ... TODO: simple challenge, write to a file and have the client echo it back? + LLSD languages = LLSD::emptyArray(); languages.append("lsl"); languages.append("luau"); @@ -243,14 +426,19 @@ void LLScriptEditorWSConnection::onOpen() LLSD features; features["live_sync"] = true; features["compilation"] = true; - features["syntax_highlight"] = true; handshake["features"] = features; - // Send editor.handshake method call to the client and handle response - call("session.handshake", handshake, [this](const LLSD& result, const LLSD& error) { + wptr_t that = shared_from_this(); + + // Send session.handshake method call and the response + call("session.handshake", handshake, [that](const LLSD& result, const LLSD& error) { if (error.isUndefined()) { - handleHandshakeResponse(result); + auto self = that.lock(); + if (self) + { + self->handleHandshakeResponse(result); + } } else { @@ -266,17 +454,7 @@ void LLScriptEditorWSConnection::onClose() { // Call parent class to clean up JSON-RPC infrastructure LLJSONRPCConnection::onClose(); - - LL_INFOS("ScriptEditorWS") << "Script editor JSON-RPC connection closed for session: " - << mEditorId << LL_ENDL; - - cleanupConnection(); - - // Clean up editor-specific state - mEditorId.clear(); - mEditorCapabilities.clear(); - mScriptId.clear(); - mEditorReady = false; + mOwningServer.reset(); // Clean up handshake response data mClientName.clear(); @@ -297,6 +475,8 @@ void LLScriptEditorWSConnection::handleHandshakeResponse(const LLSD& result) mClientVersion = result["client_version"].asString(); mProtocolVersion = result["protocol_version"].asString(); + // TODO: Validate challenge_response if implemented + // Validate protocol compatibility if (mProtocolVersion != "1.0") { @@ -307,7 +487,6 @@ void LLScriptEditorWSConnection::handleHandshakeResponse(const LLSD& result) // Store script information if provided mScriptName = result["script_name"].asString(); mScriptLanguage = result["script_language"].asString(); - mScriptId = result["script_id"].asString(); // Store supported languages for (const auto& lang : llsd::inArray( result["languages"])) @@ -326,67 +505,7 @@ void LLScriptEditorWSConnection::handleHandshakeResponse(const LLSD& result) } } - connectToEditor(mScriptId); - // Mark editor as ready - mEditorReady = true; - - LL_INFOS("ScriptEditorWS") << "Handshake completed successfully for session: " << mEditorId << LL_ENDL; -} - -bool LLScriptEditorWSConnection::connectToEditor(const std::string& script_id) -{ - LLScriptEditorWSServer::ptr_t server = std::dynamic_pointer_cast(mOwningServer.lock()); - if (!server) - { - LL_WARNS("ScriptEditorWS") << "Cannot connect to editor - server reference lost" << LL_ENDL; - return false; - } - - mEditorPanel = server->findEditorForScript(script_id); - - LLScriptEdContainer* editor_core = getEditor(); - if (!editor_core) - { - LL_INFOS("ScriptEditorWS") << "Could not find editor: " << script_id << LL_ENDL; - // TODO: Disconnect the client if no editor found - return false; - } - - return true; -} - -void LLScriptEditorWSConnection::cleanupConnection() -{ - LL_INFOS("ScriptEditorWS") << "Cleaning up connection for editor session: " << mEditorId << LL_ENDL; - - LLScriptEditorWSServer::ptr_t server = getServer(); - if (server) - { - server->dissociateEditor(mScriptId); - } - - LLScriptEdContainer* editor_core = getEditor(); - - if (editor_core) - { - editor_core->cleanupWebSocket(); - - // Notify the editor panel of disconnection - //editor_core->onExternalEditorDisconnected(); - } - - mEditorPanel = LLHandle(); -} - - -void LLScriptEditorWSConnection::sendDisconnect(S32 reason, const std::string& message) -{ - LL_INFOS("ScriptEditorWS") << "Sending disconnect message to editor (reason: " - << reason << ", message: " << message << ")" << LL_ENDL; - - LLSD params; - params["reason"] = reason; - params["message"] = message; + notify("session.ok"); - notify("session.disconnect", params); + LL_INFOS("ScriptEditorWS") << "Handshake completed successfully." << LL_ENDL; } diff --git a/indra/newview/llscripteditorws.h b/indra/newview/llscripteditorws.h index 78c675a1f4..f6e40fad6e 100644 --- a/indra/newview/llscripteditorws.h +++ b/indra/newview/llscripteditorws.h @@ -42,44 +42,30 @@ class LLLiveLSLEditor; class LLScriptEdContainer; class LLScriptEditorWSServer; -/** - * @class LLScriptEditorWSConnection - * @brief JSON-RPC WebSocket connection specialized for external script editor communication - * - * This class handles JSON-RPC 2.0 communication between the Second Life viewer - * and external script editors. It provides a clean base for implementing - * script editor integration using the standard JSON-RPC 2.0 protocol. - * - * ## Usage - * - * @code - * // Create server and let base JSON-RPC handle method registration - * auto server = std::make_shared("script_editor_server", 9020); - * - * // Register custom methods as needed - * connection->registerMethod("custom.method", handler); - * @endcode - */ -class LLScriptEditorWSConnection : public LLJSONRPCConnection, - public std::enable_shared_from_this +class LLScriptEditorWSConnection : public LLJSONRPCConnection, public std::enable_shared_from_this { public: + using ptr_t = std::shared_ptr; + using wptr_t = std::weak_ptr; + enum DisconnectReason { - REASON_NORMAL = 0, - REASON_EDITOR_CLOSED = 1, + REASON_NORMAL = 0, + REASON_EDITOR_CLOSED = 1, REASON_PROTOCOL_ERROR = 2, - REASON_TIMEOUT = 3, + REASON_TIMEOUT = 3, REASON_INTERNAL_ERROR = 4 }; - LLScriptEditorWSConnection(const LLWebsocketMgr::WSServer::ptr_t server, - const LLWebsocketMgr::connection_h& handle) - : LLJSONRPCConnection(server, handle) - { } + LLScriptEditorWSConnection(const LLWebsocketMgr::WSServer::ptr_t server, const LLWebsocketMgr::connection_h& handle) : + LLJSONRPCConnection(server, handle) + { + mConnectionID = sNextConnectionID++; + } ~LLScriptEditorWSConnection() override = default; + U32 getConnectionID() const { return mConnectionID; } // Connection lifecycle overrides void onOpen() override; @@ -100,26 +86,21 @@ private: */ void handleHandshakeResponse(const LLSD& result); - bool connectToEditor(const std::string& script_id); - void cleanupConnection(); - - LLScriptEdContainer* getEditor() const; + LLScriptEdContainer* getEditor() const; std::shared_ptr getServer() const; - std::string mEditorId; ///< Unique identifier for this editor session - LLSD mEditorCapabilities; ///< Editor capabilities metadata - std::string mScriptId; ///< Unique identifier for the script being edited - bool mEditorReady; ///< Whether editor has completed initialization - LLHandle mEditorPanel; ///< Handle to the associated LSL editor panel + U32 mConnectionID{ 0 }; ///< Unique identifier for this connection // Client handshake response data - std::string mClientName; ///< Name of the external editor client - std::string mClientVersion; ///< Version of the external editor client - std::string mProtocolVersion; ///< JSON-RPC protocol version supported by client - std::string mScriptName; ///< Name of the script being edited - std::string mScriptLanguage; ///< Programming language of the script (lsl, luau, etc.) - string_set_t mLanguages; ///< Set of supported scripting languages - string_set_t mFeatures; ///< Active client features (live_sync, compilation, etc.) + std::string mClientName; ///< Name of the external editor client + std::string mClientVersion; ///< Version of the external editor client + std::string mProtocolVersion; ///< JSON-RPC protocol version supported by client + std::string mScriptName; ///< Name of the script being edited + std::string mScriptLanguage; ///< Programming language of the script (lsl, luau, etc.) + string_set_t mLanguages; ///< Set of supported scripting languages + string_set_t mFeatures; ///< Active client features (live_sync, compilation, etc.) + + static U32 sNextConnectionID; }; /** @@ -161,21 +142,34 @@ private: class LLScriptEditorWSServer : public LLJSONRPCServer { public: + enum SubscriptionError_t + { + SUBSCRIPTION_SUCCESS = 0, + SUBSCRIPTION_INVALID_EDITOR, + SUBSCRIPTION_INVALID_SUBSCRIPTION, + SUBSCRIPTION_ALREADY_SUBSCRIBED, + SUBSCRIPTION_INTERNAL_ERROR + }; + static constexpr char const* DEFAULT_SERVER_NAME = "script_editor_server"; static constexpr U16 DEFAULT_SERVER_PORT = 9020; using ptr_t = std::shared_ptr; + using wptr_t = std::weak_ptr; LLScriptEditorWSServer(const std::string& name, U16 port, bool local_only = true); virtual ~LLScriptEditorWSServer() = default; - // Server lifecycle callbacks + void onStarted() override; + void onStopped() override; void onConnectionOpened(const LLWebsocketMgr::WSConnection::ptr_t& connection) override; void onConnectionClosed(const LLWebsocketMgr::WSConnection::ptr_t& connection) override; - bool associateEditor(const LLHandle& editor_handle, const std::string& script_id); - void dissociateEditor(const std::string& script_id); + bool subscribeScriptEditor(const LLHandle& editor_handle, const std::string &script_id); + void unsubscribeEditor(const std::string &script_id); + + void sendUnsubscribeScriptEditor(const std::string& script_id); LLHandle findEditorForScript(const std::string& script_id) const; std::shared_ptr findConnectionForScript(const std::string& script_id); @@ -186,45 +180,38 @@ public: */ std::set getActiveScripts() const; - /** - * @brief Send script content to all connected editors for a specific script - * @param script_id The script identifier - * @param content The script content - * @param metadata Optional metadata about the script - */ - void broadcastScriptUpdate(const std::string& script_id, const std::string& content, const LLSD& metadata = LLSD()); - - /** - * @brief Send compilation results to all connected editors for a specific script - * @param script_id The script identifier - * @param success Whether compilation succeeded - * @param errors Array of compilation errors/warnings - */ - void broadcastCompilationResult(const std::string& script_id, bool success, const LLSD& errors = LLSD()); - protected: LLWebsocketMgr::WSConnection::ptr_t connectionFactory(LLWebsocketMgr::WSServer::ptr_t server, LLWebsocketMgr::connection_h handle) override; - /** - * @brief Apply global method handlers to a new connection - * @param connection The connection to configure - * - * Override this method to customize which methods are registered on - * new connections. The base implementation registers all global methods, - * but derived classes can add additional script-specific methods. - */ - virtual void setupConnectionMethods(LLJSONRPCConnection::ptr_t connection) override; + void setupConnectionMethods(LLJSONRPCConnection::ptr_t connection) override; + + void broadcastLangugeChange(); + + LLSD handleLanguageIdRequest() const; + LLSD handleSyntaxRequest(const LLSD ¶ms) const; + LLSD handleScriptSubscribe(U32 connection_id, const LLSD& params); + LLSD handleScriptUnsubscribe(U32 connection_id, const LLSD& params); private: - using map_id_to_editor_t = std::unordered_map>; + struct EditorSubscription + { + LLHandle mEditorHandle; + LLScriptEditorWSConnection::wptr_t mConnection; + U32 mConnectionID{ 0 }; + }; + using subscriptions_t = std::unordered_map; + + SubscriptionError_t updateScriptSubscription(const std::string &script_id, U32 connection_id); + void unsubscribeConnection(U32 connection_id); + + subscriptions_t mSubscriptions; + std::map mActiveConnections; + + boost::signals2::connection mLanguageChangeSignal; + LLUUID mLastSyntaxId; - map_id_to_editor_t mScriptEditors; - std::set> mActiveConnections; - /** - * @brief Connection timeout management - */ LLTimer mCleanupTimer; static constexpr F32 CLEANUP_INTERVAL = 60.0f; // seconds static constexpr F32 CONNECTION_TIMEOUT = 300.0f; // 5 minutes diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index 1f8766eea2..a891bf945e 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -343,7 +343,7 @@ void LLSyntaxLua::initialize() if (mInitialized) return; loadDefaultKeywordsIntoLLSD(); - + loadLuaTypesIntoLLSD(); mInitialized = true; } @@ -361,3 +361,18 @@ void LLSyntaxLua::loadDefaultKeywordsIntoLLSD() } } } + +void LLSyntaxLua::loadLuaTypesIntoLLSD() +{ + std::string fullFileSpec = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "types_lua_default.llsd"); + llifstream file(fullFileSpec.c_str()); + + if (file.good()) + { + LLSD content; + if (LLSDSerialize::fromXML(content, file) != LLSDParser::PARSE_FAILURE) + { + mTypesXml = content; + } + } +} diff --git a/indra/newview/llsyntaxid.h b/indra/newview/llsyntaxid.h index c24cea1776..51103e3396 100644 --- a/indra/newview/llsyntaxid.h +++ b/indra/newview/llsyntaxid.h @@ -41,11 +41,20 @@ class LLSyntaxIdLSL : public LLSingleton LLSINGLETON(LLSyntaxIdLSL); friend class fetchKeywordsFileResponder; +public: + using syntax_id_changed_signal_t = boost::signals2::signal; + using syntax_id_changed_h = boost::signals2::connection; + + void initialize(); + bool keywordFetchInProgress(); + LLSD getKeywordsXML() const { return mKeywordsXml; }; + LLUUID getSyntaxID() const { return mSyntaxId; } + syntax_id_changed_h addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb); + private: std::set mInflightFetches; - typedef boost::signals2::signal syntax_id_changed_signal_t; syntax_id_changed_signal_t mSyntaxIDChangedSignal; - boost::signals2::connection mRegionChangedCallback; + syntax_id_changed_h mRegionChangedCallback; bool syntaxIdChanged(); bool isSupportedVersion(const LLSD& content); @@ -67,11 +76,6 @@ private: LLSD mKeywordsXml; bool mInitialized; -public: - void initialize(); - bool keywordFetchInProgress(); - LLSD getKeywordsXML() const { return mKeywordsXml; }; - boost::signals2::connection addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb); }; @@ -82,11 +86,13 @@ class LLSyntaxLua : public LLSingleton public: void initialize(); LLSD getKeywordsXML() const { return mKeywordsXml; } + LLSD getTypesXML() const { return mTypesXml; } private: void loadDefaultKeywordsIntoLLSD(); - + void loadLuaTypesIntoLLSD(); LLSD mKeywordsXml; + LLSD mTypesXml; bool mInitialized; }; -- cgit v1.3 From 5306ad767bc1cc768145074aac25944c6059b3c2 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 8 Oct 2025 17:42:32 -0700 Subject: Renamed types_lua_default.llsd to types_lua_default.xml, returning an empty lang def is not a success. Hopefully this will package correctly. --- indra/newview/CMakeLists.txt | 2 +- indra/newview/app_settings/types_lua_default.llsd | 2488 --------------------- indra/newview/app_settings/types_lua_default.xml | 2488 +++++++++++++++++++++ indra/newview/llscripteditorws.cpp | 4 +- indra/newview/llsyntaxid.cpp | 2 +- 5 files changed, 2492 insertions(+), 2492 deletions(-) delete mode 100644 indra/newview/app_settings/types_lua_default.llsd create mode 100644 indra/newview/app_settings/types_lua_default.xml (limited to 'indra/newview/llsyntaxid.cpp') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 702a738e57..87e350a69d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1674,7 +1674,7 @@ set(viewer_APPSETTINGS_FILES app_settings/std_bump.ini app_settings/toolbars.xml app_settings/trees.xml - app_settings/types_lua_default.llsd + app_settings/types_lua_default.xml app_settings/viewerart.xml app_settings/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg diff --git a/indra/newview/app_settings/types_lua_default.llsd b/indra/newview/app_settings/types_lua_default.llsd deleted file mode 100644 index 5881df5ba5..0000000000 --- a/indra/newview/app_settings/types_lua_default.llsd +++ /dev/null @@ -1,2488 +0,0 @@ - - - - $schema - ./sl-lua-defs.schema.json - aliases - - list - - aliasTypes - - string - number - integer - vector - uuid - quaternion - boolean - - aliasIndex - number - tooltip - A table with numeric indices containing various value types - - table - - aliasTypes - - any - - aliasIndex - any - tooltip - A table with any type of indices and values - - numeric - - aliasTypes - - number - boolean - integer - - tooltip - A union type representing numeric values - - lljson_constant - - aliasTypes - - number - - tooltip - A constant value used in lljson module - - uuid_like - - aliasTypes - - string - uuid - - tooltip - A union type representing uuid values - - EventHandler - - aliasTypes - - (...any) -> () - - tooltip - A function type for event handlers that accepts variable arguments - - - functions - - toquaternion - - parameters - - - name - str - type - string - - - returnType - quaternion | nil - tooltip - Creates a quaternion from a string argument in format `<1,1,1,1>`. Invalid strings will return `nil`. Due to an old error from LSL, strings that match up to the closing `>` are interpreted as valid. So `<1,1,1,1` and `<1,1,1,1spoon` are both cast to `<1,1,1,1>`. When testing if a string is a quaternion or a vector, you should test with `toquaternion` first. - - tovector - - parameters - - - name - str - type - string - - - returnType - vector | nil - tooltip - Creates a vector from a string argument in format `<1,1,1>`. Invalid strings will return `nil`. Due to an old error from LSL, strings that match up to the closing `>` are interpreted as valid. So `<1,1,1`, `<1,1,1,1` and `<1,1,1spoon` are all cast to `<1,1,1>`. When testing if a string is a quaternion or a vector, you should test with `toquaternion` first. - - integer - - parameters - - - name - value - type - string | number - - - returnType - integer - tooltip - Creates an integer value from argument - - uuid - - parameters - - - name - str - type - string - - - returnType - uuid - tooltip - Creates a uuid from a string argument - - vector - - parameters - - - name - x - type - number - - - name - y - type - number - - - name - z - type - number - - - returnType - vector - tooltip - Creates a vector. - - quaternion - - parameters - - - name - x - type - number - - - name - y - type - number - - - name - z - type - number - - - name - s - type - number - - - returnType - quaternion - tooltip - Creates a quaternion rotation. - - - classes - - integer - - methods - - __add - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Addition operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - number - tooltip - Addition operator for integer and number - - - __sub - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Subtraction operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - number - tooltip - Subtraction operator for integer and number - - - __mul - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Multiplication operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - number - tooltip - Multiplication operator for integer and number - - - __div - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Division operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - number - tooltip - Division operator for integer and number - - - __unm - - - parameters - - - name - self - type - integer - - - returnType - integer - tooltip - Unary minus operator - - - __mod - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Modulo operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - number - tooltip - Modulo operator for integer and number - - - __pow - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Power operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - number - tooltip - Power operator for integer and number - - - __idiv - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - integer - tooltip - Integer division operator for integers - - - parameters - - - name - self - type - integer - - - name - other - type - number - - - returnType - integer - tooltip - Integer division operator for integer and number - - - __eq - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - boolean - tooltip - Equality comparison operator - - - __lt - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - boolean - tooltip - Less than comparison operator - - - __le - - - parameters - - - name - self - type - integer - - - name - other - type - integer - - - returnType - boolean - tooltip - Less than or equal comparison operator - - - - tooltip - Integer class with arithmetic and comparison operators - - uuid - - methods - - __tostring - - - parameters - - - name - self - type - uuid - - - returnType - string - tooltip - Convert UUID to string representation - - - - properties - - istruthy - boolean - - tooltip - UUID class with string conversion and truthiness property - - quaternion - - properties - - x - number - y - number - z - number - s - number - - methods - - __mul - - - parameters - - - name - self - type - quaternion - - - name - other - type - vector - - - returnType - vector - tooltip - Multiply vector by quaternion - - - parameters - - - name - self - type - quaternion - - - name - other - type - quaternion - - - returnType - quaternion - tooltip - Multiply quaternion by quaternion - - - - tooltip - Quaternion class representing a rotation with x, y, z, s components - - vector - - properties - - x - number - y - number - z - number - - methods - - __mul - - - parameters - - - name - self - type - vector - - - name - other - type - vector - - - returnType - vector - tooltip - Multiply vector by vector - - - parameters - - - name - self - type - vector - - - name - other - type - quaternion - - - returnType - vector - tooltip - Multiply vector by quaternion - - - parameters - - - name - self - type - vector - - - name - other - type - number - - - returnType - vector - tooltip - Multiply vector by number - - - __div - - - parameters - - - name - self - type - vector - - - name - other - type - vector - - - returnType - vector - tooltip - Divide vector by vector - - - parameters - - - name - self - type - vector - - - name - other - type - quaternion - - - returnType - vector - tooltip - Divide vector by quaternion - - - parameters - - - name - self - type - vector - - - name - other - type - number - - - returnType - vector - tooltip - Divide vector by number - - - __idiv - - - parameters - - - name - self - type - vector - - - name - other - type - vector - - - returnType - vector - tooltip - Floor divide vector by vector - - - parameters - - - name - self - type - vector - - - name - other - type - quaternion - - - returnType - vector - tooltip - Floor divide vector by quaternion - - - parameters - - - name - self - type - vector - - - name - other - type - number - - - returnType - vector - tooltip - Floor divide vector by number - - - __add - - - parameters - - - name - self - type - vector - - - name - other - type - vector - - - returnType - vector - tooltip - Add two vectors - - - __sub - - - parameters - - - name - self - type - vector - - - name - other - type - vector - - - returnType - vector - tooltip - Subtract vector from vector - - - __unm - - - parameters - - - name - self - type - vector - - - returnType - vector - tooltip - Negate a vector - - - - tooltip - Vector class representing a 3D vector with x, y, z components - - DetectedEvent - - properties - - index - number - valid - boolean - canAdjustDamage - boolean - - methods - - adjustDamage - - - parameters - - - name - self - type - DetectedEvent - - - name - damage - type - number - - - returnType - () - tooltip - Adjusts the damage amount for this detected event - - - getOwner - - - parameters - - - name - self - type - DetectedEvent - - - returnType - any - tooltip - Gets the owner of the detected object - - - getName - - - parameters - - - name - self - type - DetectedEvent - - - returnType - any - tooltip - Gets the name of the detected object - - - getFace - - - parameters - - - name - self - type - DetectedEvent - - - returnType - any - tooltip - Gets the face number of the detected collision/touch - - - getLinkNumber - - - parameters - - - name - self - type - DetectedEvent - - - returnType - any - tooltip - Gets the link number of the detected object - - - getKey - - - parameters - - - name - self - type - DetectedEvent - - - returnType - any - tooltip - Gets the key/UUID of the detected object - - - new - - - parameters - - - name - self - type - DetectedEvent - - - name - index - type - number - - - name - canAdjustDamage - type - boolean - - - returnType - DetectedEvent - tooltip - Creates a new DetectedEvent instance - - - - tooltip - DetectedEvent class for handling multi-event handlers like touch, collision, sensor events - - LLEvents - - properties - - _handlers - { [string]: { EventHandler } } - - methods - - on - - - parameters - - - name - self - type - LLEvents - - - name - event_name - type - string - - - name - handler - type - EventHandler - - - returnType - EventHandler - tooltip - Registers a persistent event handler for the specified event - - - once - - - parameters - - - name - self - type - LLEvents - - - name - event_name - type - string - - - name - handler - type - EventHandler - - - returnType - EventHandler - tooltip - Registers a one-time event handler that will be automatically removed after first execution - - - off - - - parameters - - - name - self - type - LLEvents - - - name - event_name - type - string - - - name - handler - type - EventHandler - optional - 1 - - - returnType - boolean - tooltip - Removes an event handler and returns true if successful - - - listeners - - - parameters - - - name - self - type - LLEvents - - - name - event_name - type - string - - - returnType - { EventHandler } - tooltip - Returns a copy of all handlers registered for the specified event - - - eventNames - - - parameters - - - name - self - type - LLEvents - - - returnType - { string } - tooltip - Returns an array of all event names that have registered handlers - - - - tooltip - LLEvents interface providing dynamic event handler management for Second Life scripts - - LLTimers - - properties - - _timers - { _LLTimerData } - - methods - - on - - - parameters - - - name - self - type - LLTimers - - - name - seconds - type - number - - - name - handler - type - EventHandler - - - returnType - EventHandler - tooltip - Registers a repeating timer that will call the handler every specified number of seconds - - - once - - - parameters - - - name - self - type - LLTimers - - - name - seconds - type - number - - - name - handler - type - EventHandler - - - returnType - EventHandler - tooltip - Registers a one-shot timer that will call the handler once after the specified delay - - - off - - - parameters - - - name - self - type - LLTimers - - - name - handler - type - EventHandler - optional - 1 - - - returnType - boolean - tooltip - Removes a timer handler and returns true if successful - - - - tooltip - LLTimers interface providing timer management for Second Life scripts - - _LLTimerData - - properties - - handler - EventHandler - nextRun - number - interval - number | nil - - tooltip - Internal timer data structure containing handler function and timing information - - - modules - - bit32 - - methods - - arshift - - - parameters - - - name - n - type - integer - - - name - i - type - integer - - - returnType - integer - tooltip - Arithmetic right shift for integers - - - parameters - - - name - n - type - integer | number - - - name - i - type - integer | number - - - returnType - number - tooltip - Arithmetic right shift for mixed types - - - band - - - parameters - - - name - args - type - integer - variadic - 1 - - - returnType - integer - tooltip - Bitwise AND for integers - - - parameters - - - name - args - type - integer | number - variadic - 1 - - - returnType - number - tooltip - Bitwise AND for mixed types - - - bnot - - - parameters - - - name - n - type - integer - - - returnType - integer - tooltip - Bitwise NOT for integers - - - parameters - - - name - n - type - integer | number - - - returnType - number - tooltip - Bitwise NOT for mixed types - - - bor - - - parameters - - - name - args - type - integer - variadic - 1 - - - returnType - integer - tooltip - Bitwise OR for integers - - - parameters - - - name - args - type - integer | number - variadic - 1 - - - returnType - number - tooltip - Bitwise OR for mixed types - - - bxor - - - parameters - - - name - args - type - integer - variadic - 1 - - - returnType - integer - tooltip - Bitwise XOR for integers - - - parameters - - - name - args - type - integer | number - variadic - 1 - - - returnType - number - tooltip - Bitwise XOR for mixed types - - - btest - - - parameters - - - name - args - type - integer | number - variadic - 1 - - - returnType - boolean - tooltip - Test if bitwise AND is non-zero - - - extract - - - parameters - - - name - n - type - integer - - - name - f - type - integer - - - name - w - type - integer - - - returnType - integer - tooltip - Extract bits from integer - - - parameters - - - name - n - type - integer | number - - - name - f - type - integer | number - - - name - w - type - integer | number - - - returnType - number - tooltip - Extract bits from mixed types - - - lrotate - - - parameters - - - name - n - type - integer - - - name - i - type - integer - - - returnType - integer - tooltip - Left rotate for integers - - - parameters - - - name - n - type - integer | number - - - name - i - type - integer | number - - - returnType - number - tooltip - Left rotate for mixed types - - - lshift - - - parameters - - - name - n - type - integer - - - name - i - type - integer - - - returnType - integer - tooltip - Left shift for integers - - - parameters - - - name - n - type - integer | number - - - name - i - type - integer | number - - - returnType - number - tooltip - Left shift for mixed types - - - replace - - - parameters - - - name - n - type - integer - - - name - r - type - integer - - - name - f - type - integer - - - name - w - type - integer - optional - 1 - - - returnType - integer - tooltip - Replace bits in integer - - - parameters - - - name - n - type - integer | number - - - name - r - type - integer | number - - - name - f - type - integer | number - - - name - w - type - integer | number - optional - 1 - - - returnType - number - tooltip - Replace bits in mixed types - - - rrotate - - - parameters - - - name - n - type - integer - - - name - i - type - integer - - - returnType - integer - tooltip - Right rotate for integers - - - parameters - - - name - n - type - integer | number - - - name - i - type - integer | number - - - returnType - number - tooltip - Right rotate for mixed types - - - rshift - - - parameters - - - name - n - type - integer - - - name - i - type - integer - - - returnType - integer - tooltip - Right shift for integers - - - parameters - - - name - n - type - integer | number - - - name - i - type - integer | number - - - returnType - number - tooltip - Right shift for mixed types - - - countlz - - - parameters - - - name - n - type - integer - - - returnType - integer - tooltip - Count leading zeros for integers - - - parameters - - - name - n - type - number - - - returnType - integer - tooltip - Count leading zeros for numbers - - - countrz - - - parameters - - - name - n - type - integer - - - returnType - integer - tooltip - Count trailing zeros for integers - - - parameters - - - name - n - type - number - - - returnType - integer - tooltip - Count trailing zeros for numbers - - - byteswap - - - parameters - - - name - n - type - integer - - - returnType - integer - tooltip - Byte swap for integers - - - parameters - - - name - n - type - number - - - returnType - integer - tooltip - Byte swap for numbers - - - - tooltip - Bitwise operations library providing bit manipulation functions - - vector - - properties - - one - vector - zero - vector - - methods - - abs - - - parameters - - - name - vec - type - vector - - - returnType - vector - tooltip - Applies math.abs to every component of the input vector - - - angle - - - parameters - - - name - vec1 - type - vector - - - name - vec2 - type - vector - - - name - axis - type - vector - optional - 1 - - - returnType - number - tooltip - Computes the angle between two vectors in radians. The axis, if specified, is used to determine the sign of the angle - - - ceil - - - parameters - - - name - vec - type - vector - - - returnType - vector - tooltip - Applies math.ceil to every component of the input vector - - - clamp - - - parameters - - - name - vec - type - vector - - - name - min - type - vector - - - name - max - type - vector - - - returnType - vector - tooltip - Applies math.clamp to every component of the input vector - - - create - - - parameters - - - name - x - type - number | integer - - - name - y - type - number | integer - - - name - z - type - number | integer - - - returnType - vector - tooltip - Creates a new vector with the given component values - - - cross - - - parameters - - - name - vec1 - type - vector - - - name - vec2 - type - vector - - - returnType - vector - tooltip - Computes the cross product of two vectors - - - dot - - - parameters - - - name - vec1 - type - vector - - - name - vec2 - type - vector - - - returnType - number - tooltip - Computes the dot product of two vectors - - - floor - - - parameters - - - name - vec - type - vector - - - returnType - vector - tooltip - Applies math.floor to every component of the input vector - - - magnitude - - - parameters - - - name - vec - type - vector - - - returnType - number - tooltip - Calculates the magnitude of a given vector - - - max - - - parameters - - - name - args - type - vector - variadic - 1 - - - returnType - vector - tooltip - Applies math.max to the corresponding components of the input vectors - - - min - - - parameters - - - name - args - type - vector - variadic - 1 - - - returnType - vector - tooltip - Applies math.min to the corresponding components of the input vectors - - - normalize - - - parameters - - - name - vec - type - vector - - - returnType - vector - tooltip - Computes the normalized version (unit vector) of a given vector - - - sign - - - parameters - - - name - vec - type - vector - - - returnType - vector - tooltip - Applies math.sign to every component of the input vector - - - - tooltip - Vector utility functions for operations on vectors - - lljson - - properties - - empty_array - lljson_constant - null - lljson_constant - - methods - - decode - - - parameters - - - name - json - type - string - - - returnType - string | number | integer | vector | uuid | quaternion | boolean | table | nil - tooltip - Decode JSON string to Lua value - - - encode - - - parameters - - - name - value - type - string | number | integer | vector | uuid | quaternion | boolean | table | nil - - - returnType - string - tooltip - Encode Lua value as JSON - - - - tooltip - JSON encoding and decoding module with constants for null and empty arrays - - llbase64 - - methods - - decode - - - parameters - - - name - base64 - type - string - - - returnType - string - tooltip - Decode a base64 string to a string - - - parameters - - - name - base64 - type - string - - - name - asBuffer - type - true - - - returnType - buffer - tooltip - Decode a base64 string to a buffer - - - parameters - - - name - base64 - type - string - - - name - asBuffer - type - false - - - returnType - string - tooltip - Decode a base64 string to a string - - - encode - - - parameters - - - name - value - type - string | buffer - - - returnType - string - tooltip - Encode a string or buffer to base64 - - - - tooltip - Base64 encoding and decoding module for strings and buffers - - - - diff --git a/indra/newview/app_settings/types_lua_default.xml b/indra/newview/app_settings/types_lua_default.xml new file mode 100644 index 0000000000..5881df5ba5 --- /dev/null +++ b/indra/newview/app_settings/types_lua_default.xml @@ -0,0 +1,2488 @@ + + + + $schema + ./sl-lua-defs.schema.json + aliases + + list + + aliasTypes + + string + number + integer + vector + uuid + quaternion + boolean + + aliasIndex + number + tooltip + A table with numeric indices containing various value types + + table + + aliasTypes + + any + + aliasIndex + any + tooltip + A table with any type of indices and values + + numeric + + aliasTypes + + number + boolean + integer + + tooltip + A union type representing numeric values + + lljson_constant + + aliasTypes + + number + + tooltip + A constant value used in lljson module + + uuid_like + + aliasTypes + + string + uuid + + tooltip + A union type representing uuid values + + EventHandler + + aliasTypes + + (...any) -> () + + tooltip + A function type for event handlers that accepts variable arguments + + + functions + + toquaternion + + parameters + + + name + str + type + string + + + returnType + quaternion | nil + tooltip + Creates a quaternion from a string argument in format `<1,1,1,1>`. Invalid strings will return `nil`. Due to an old error from LSL, strings that match up to the closing `>` are interpreted as valid. So `<1,1,1,1` and `<1,1,1,1spoon` are both cast to `<1,1,1,1>`. When testing if a string is a quaternion or a vector, you should test with `toquaternion` first. + + tovector + + parameters + + + name + str + type + string + + + returnType + vector | nil + tooltip + Creates a vector from a string argument in format `<1,1,1>`. Invalid strings will return `nil`. Due to an old error from LSL, strings that match up to the closing `>` are interpreted as valid. So `<1,1,1`, `<1,1,1,1` and `<1,1,1spoon` are all cast to `<1,1,1>`. When testing if a string is a quaternion or a vector, you should test with `toquaternion` first. + + integer + + parameters + + + name + value + type + string | number + + + returnType + integer + tooltip + Creates an integer value from argument + + uuid + + parameters + + + name + str + type + string + + + returnType + uuid + tooltip + Creates a uuid from a string argument + + vector + + parameters + + + name + x + type + number + + + name + y + type + number + + + name + z + type + number + + + returnType + vector + tooltip + Creates a vector. + + quaternion + + parameters + + + name + x + type + number + + + name + y + type + number + + + name + z + type + number + + + name + s + type + number + + + returnType + quaternion + tooltip + Creates a quaternion rotation. + + + classes + + integer + + methods + + __add + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Addition operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + number + tooltip + Addition operator for integer and number + + + __sub + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Subtraction operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + number + tooltip + Subtraction operator for integer and number + + + __mul + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Multiplication operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + number + tooltip + Multiplication operator for integer and number + + + __div + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Division operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + number + tooltip + Division operator for integer and number + + + __unm + + + parameters + + + name + self + type + integer + + + returnType + integer + tooltip + Unary minus operator + + + __mod + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Modulo operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + number + tooltip + Modulo operator for integer and number + + + __pow + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Power operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + number + tooltip + Power operator for integer and number + + + __idiv + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + integer + tooltip + Integer division operator for integers + + + parameters + + + name + self + type + integer + + + name + other + type + number + + + returnType + integer + tooltip + Integer division operator for integer and number + + + __eq + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + boolean + tooltip + Equality comparison operator + + + __lt + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + boolean + tooltip + Less than comparison operator + + + __le + + + parameters + + + name + self + type + integer + + + name + other + type + integer + + + returnType + boolean + tooltip + Less than or equal comparison operator + + + + tooltip + Integer class with arithmetic and comparison operators + + uuid + + methods + + __tostring + + + parameters + + + name + self + type + uuid + + + returnType + string + tooltip + Convert UUID to string representation + + + + properties + + istruthy + boolean + + tooltip + UUID class with string conversion and truthiness property + + quaternion + + properties + + x + number + y + number + z + number + s + number + + methods + + __mul + + + parameters + + + name + self + type + quaternion + + + name + other + type + vector + + + returnType + vector + tooltip + Multiply vector by quaternion + + + parameters + + + name + self + type + quaternion + + + name + other + type + quaternion + + + returnType + quaternion + tooltip + Multiply quaternion by quaternion + + + + tooltip + Quaternion class representing a rotation with x, y, z, s components + + vector + + properties + + x + number + y + number + z + number + + methods + + __mul + + + parameters + + + name + self + type + vector + + + name + other + type + vector + + + returnType + vector + tooltip + Multiply vector by vector + + + parameters + + + name + self + type + vector + + + name + other + type + quaternion + + + returnType + vector + tooltip + Multiply vector by quaternion + + + parameters + + + name + self + type + vector + + + name + other + type + number + + + returnType + vector + tooltip + Multiply vector by number + + + __div + + + parameters + + + name + self + type + vector + + + name + other + type + vector + + + returnType + vector + tooltip + Divide vector by vector + + + parameters + + + name + self + type + vector + + + name + other + type + quaternion + + + returnType + vector + tooltip + Divide vector by quaternion + + + parameters + + + name + self + type + vector + + + name + other + type + number + + + returnType + vector + tooltip + Divide vector by number + + + __idiv + + + parameters + + + name + self + type + vector + + + name + other + type + vector + + + returnType + vector + tooltip + Floor divide vector by vector + + + parameters + + + name + self + type + vector + + + name + other + type + quaternion + + + returnType + vector + tooltip + Floor divide vector by quaternion + + + parameters + + + name + self + type + vector + + + name + other + type + number + + + returnType + vector + tooltip + Floor divide vector by number + + + __add + + + parameters + + + name + self + type + vector + + + name + other + type + vector + + + returnType + vector + tooltip + Add two vectors + + + __sub + + + parameters + + + name + self + type + vector + + + name + other + type + vector + + + returnType + vector + tooltip + Subtract vector from vector + + + __unm + + + parameters + + + name + self + type + vector + + + returnType + vector + tooltip + Negate a vector + + + + tooltip + Vector class representing a 3D vector with x, y, z components + + DetectedEvent + + properties + + index + number + valid + boolean + canAdjustDamage + boolean + + methods + + adjustDamage + + + parameters + + + name + self + type + DetectedEvent + + + name + damage + type + number + + + returnType + () + tooltip + Adjusts the damage amount for this detected event + + + getOwner + + + parameters + + + name + self + type + DetectedEvent + + + returnType + any + tooltip + Gets the owner of the detected object + + + getName + + + parameters + + + name + self + type + DetectedEvent + + + returnType + any + tooltip + Gets the name of the detected object + + + getFace + + + parameters + + + name + self + type + DetectedEvent + + + returnType + any + tooltip + Gets the face number of the detected collision/touch + + + getLinkNumber + + + parameters + + + name + self + type + DetectedEvent + + + returnType + any + tooltip + Gets the link number of the detected object + + + getKey + + + parameters + + + name + self + type + DetectedEvent + + + returnType + any + tooltip + Gets the key/UUID of the detected object + + + new + + + parameters + + + name + self + type + DetectedEvent + + + name + index + type + number + + + name + canAdjustDamage + type + boolean + + + returnType + DetectedEvent + tooltip + Creates a new DetectedEvent instance + + + + tooltip + DetectedEvent class for handling multi-event handlers like touch, collision, sensor events + + LLEvents + + properties + + _handlers + { [string]: { EventHandler } } + + methods + + on + + + parameters + + + name + self + type + LLEvents + + + name + event_name + type + string + + + name + handler + type + EventHandler + + + returnType + EventHandler + tooltip + Registers a persistent event handler for the specified event + + + once + + + parameters + + + name + self + type + LLEvents + + + name + event_name + type + string + + + name + handler + type + EventHandler + + + returnType + EventHandler + tooltip + Registers a one-time event handler that will be automatically removed after first execution + + + off + + + parameters + + + name + self + type + LLEvents + + + name + event_name + type + string + + + name + handler + type + EventHandler + optional + 1 + + + returnType + boolean + tooltip + Removes an event handler and returns true if successful + + + listeners + + + parameters + + + name + self + type + LLEvents + + + name + event_name + type + string + + + returnType + { EventHandler } + tooltip + Returns a copy of all handlers registered for the specified event + + + eventNames + + + parameters + + + name + self + type + LLEvents + + + returnType + { string } + tooltip + Returns an array of all event names that have registered handlers + + + + tooltip + LLEvents interface providing dynamic event handler management for Second Life scripts + + LLTimers + + properties + + _timers + { _LLTimerData } + + methods + + on + + + parameters + + + name + self + type + LLTimers + + + name + seconds + type + number + + + name + handler + type + EventHandler + + + returnType + EventHandler + tooltip + Registers a repeating timer that will call the handler every specified number of seconds + + + once + + + parameters + + + name + self + type + LLTimers + + + name + seconds + type + number + + + name + handler + type + EventHandler + + + returnType + EventHandler + tooltip + Registers a one-shot timer that will call the handler once after the specified delay + + + off + + + parameters + + + name + self + type + LLTimers + + + name + handler + type + EventHandler + optional + 1 + + + returnType + boolean + tooltip + Removes a timer handler and returns true if successful + + + + tooltip + LLTimers interface providing timer management for Second Life scripts + + _LLTimerData + + properties + + handler + EventHandler + nextRun + number + interval + number | nil + + tooltip + Internal timer data structure containing handler function and timing information + + + modules + + bit32 + + methods + + arshift + + + parameters + + + name + n + type + integer + + + name + i + type + integer + + + returnType + integer + tooltip + Arithmetic right shift for integers + + + parameters + + + name + n + type + integer | number + + + name + i + type + integer | number + + + returnType + number + tooltip + Arithmetic right shift for mixed types + + + band + + + parameters + + + name + args + type + integer + variadic + 1 + + + returnType + integer + tooltip + Bitwise AND for integers + + + parameters + + + name + args + type + integer | number + variadic + 1 + + + returnType + number + tooltip + Bitwise AND for mixed types + + + bnot + + + parameters + + + name + n + type + integer + + + returnType + integer + tooltip + Bitwise NOT for integers + + + parameters + + + name + n + type + integer | number + + + returnType + number + tooltip + Bitwise NOT for mixed types + + + bor + + + parameters + + + name + args + type + integer + variadic + 1 + + + returnType + integer + tooltip + Bitwise OR for integers + + + parameters + + + name + args + type + integer | number + variadic + 1 + + + returnType + number + tooltip + Bitwise OR for mixed types + + + bxor + + + parameters + + + name + args + type + integer + variadic + 1 + + + returnType + integer + tooltip + Bitwise XOR for integers + + + parameters + + + name + args + type + integer | number + variadic + 1 + + + returnType + number + tooltip + Bitwise XOR for mixed types + + + btest + + + parameters + + + name + args + type + integer | number + variadic + 1 + + + returnType + boolean + tooltip + Test if bitwise AND is non-zero + + + extract + + + parameters + + + name + n + type + integer + + + name + f + type + integer + + + name + w + type + integer + + + returnType + integer + tooltip + Extract bits from integer + + + parameters + + + name + n + type + integer | number + + + name + f + type + integer | number + + + name + w + type + integer | number + + + returnType + number + tooltip + Extract bits from mixed types + + + lrotate + + + parameters + + + name + n + type + integer + + + name + i + type + integer + + + returnType + integer + tooltip + Left rotate for integers + + + parameters + + + name + n + type + integer | number + + + name + i + type + integer | number + + + returnType + number + tooltip + Left rotate for mixed types + + + lshift + + + parameters + + + name + n + type + integer + + + name + i + type + integer + + + returnType + integer + tooltip + Left shift for integers + + + parameters + + + name + n + type + integer | number + + + name + i + type + integer | number + + + returnType + number + tooltip + Left shift for mixed types + + + replace + + + parameters + + + name + n + type + integer + + + name + r + type + integer + + + name + f + type + integer + + + name + w + type + integer + optional + 1 + + + returnType + integer + tooltip + Replace bits in integer + + + parameters + + + name + n + type + integer | number + + + name + r + type + integer | number + + + name + f + type + integer | number + + + name + w + type + integer | number + optional + 1 + + + returnType + number + tooltip + Replace bits in mixed types + + + rrotate + + + parameters + + + name + n + type + integer + + + name + i + type + integer + + + returnType + integer + tooltip + Right rotate for integers + + + parameters + + + name + n + type + integer | number + + + name + i + type + integer | number + + + returnType + number + tooltip + Right rotate for mixed types + + + rshift + + + parameters + + + name + n + type + integer + + + name + i + type + integer + + + returnType + integer + tooltip + Right shift for integers + + + parameters + + + name + n + type + integer | number + + + name + i + type + integer | number + + + returnType + number + tooltip + Right shift for mixed types + + + countlz + + + parameters + + + name + n + type + integer + + + returnType + integer + tooltip + Count leading zeros for integers + + + parameters + + + name + n + type + number + + + returnType + integer + tooltip + Count leading zeros for numbers + + + countrz + + + parameters + + + name + n + type + integer + + + returnType + integer + tooltip + Count trailing zeros for integers + + + parameters + + + name + n + type + number + + + returnType + integer + tooltip + Count trailing zeros for numbers + + + byteswap + + + parameters + + + name + n + type + integer + + + returnType + integer + tooltip + Byte swap for integers + + + parameters + + + name + n + type + number + + + returnType + integer + tooltip + Byte swap for numbers + + + + tooltip + Bitwise operations library providing bit manipulation functions + + vector + + properties + + one + vector + zero + vector + + methods + + abs + + + parameters + + + name + vec + type + vector + + + returnType + vector + tooltip + Applies math.abs to every component of the input vector + + + angle + + + parameters + + + name + vec1 + type + vector + + + name + vec2 + type + vector + + + name + axis + type + vector + optional + 1 + + + returnType + number + tooltip + Computes the angle between two vectors in radians. The axis, if specified, is used to determine the sign of the angle + + + ceil + + + parameters + + + name + vec + type + vector + + + returnType + vector + tooltip + Applies math.ceil to every component of the input vector + + + clamp + + + parameters + + + name + vec + type + vector + + + name + min + type + vector + + + name + max + type + vector + + + returnType + vector + tooltip + Applies math.clamp to every component of the input vector + + + create + + + parameters + + + name + x + type + number | integer + + + name + y + type + number | integer + + + name + z + type + number | integer + + + returnType + vector + tooltip + Creates a new vector with the given component values + + + cross + + + parameters + + + name + vec1 + type + vector + + + name + vec2 + type + vector + + + returnType + vector + tooltip + Computes the cross product of two vectors + + + dot + + + parameters + + + name + vec1 + type + vector + + + name + vec2 + type + vector + + + returnType + number + tooltip + Computes the dot product of two vectors + + + floor + + + parameters + + + name + vec + type + vector + + + returnType + vector + tooltip + Applies math.floor to every component of the input vector + + + magnitude + + + parameters + + + name + vec + type + vector + + + returnType + number + tooltip + Calculates the magnitude of a given vector + + + max + + + parameters + + + name + args + type + vector + variadic + 1 + + + returnType + vector + tooltip + Applies math.max to the corresponding components of the input vectors + + + min + + + parameters + + + name + args + type + vector + variadic + 1 + + + returnType + vector + tooltip + Applies math.min to the corresponding components of the input vectors + + + normalize + + + parameters + + + name + vec + type + vector + + + returnType + vector + tooltip + Computes the normalized version (unit vector) of a given vector + + + sign + + + parameters + + + name + vec + type + vector + + + returnType + vector + tooltip + Applies math.sign to every component of the input vector + + + + tooltip + Vector utility functions for operations on vectors + + lljson + + properties + + empty_array + lljson_constant + null + lljson_constant + + methods + + decode + + + parameters + + + name + json + type + string + + + returnType + string | number | integer | vector | uuid | quaternion | boolean | table | nil + tooltip + Decode JSON string to Lua value + + + encode + + + parameters + + + name + value + type + string | number | integer | vector | uuid | quaternion | boolean | table | nil + + + returnType + string + tooltip + Encode Lua value as JSON + + + + tooltip + JSON encoding and decoding module with constants for null and empty arrays + + llbase64 + + methods + + decode + + + parameters + + + name + base64 + type + string + + + returnType + string + tooltip + Decode a base64 string to a string + + + parameters + + + name + base64 + type + string + + + name + asBuffer + type + true + + + returnType + buffer + tooltip + Decode a base64 string to a buffer + + + parameters + + + name + base64 + type + string + + + name + asBuffer + type + false + + + returnType + string + tooltip + Decode a base64 string to a string + + + encode + + + parameters + + + name + value + type + string | buffer + + + returnType + string + tooltip + Encode a string or buffer to base64 + + + + tooltip + Base64 encoding and decoding module for strings and buffers + + + + diff --git a/indra/newview/llscripteditorws.cpp b/indra/newview/llscripteditorws.cpp index cecac23383..814157e86c 100644 --- a/indra/newview/llscripteditorws.cpp +++ b/indra/newview/llscripteditorws.cpp @@ -334,12 +334,12 @@ LLSD LLScriptEditorWSServer::handleSyntaxRequest(const LLSD& params) const if (category == "defs.lua") { response["defs"] = LLSyntaxLua::instance().getTypesXML(); - response["success"] = true; + response["success"] = response["defs"].isDefined(); } else if (category == "defs.lsl") { response["defs"] = LLSyntaxIdLSL::instance().getKeywordsXML(); - response["success"] = true; + response["success"] = response["defs"].isDefined(); } else { diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index a891bf945e..bca3f0abc8 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -364,7 +364,7 @@ void LLSyntaxLua::loadDefaultKeywordsIntoLLSD() void LLSyntaxLua::loadLuaTypesIntoLLSD() { - std::string fullFileSpec = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "types_lua_default.llsd"); + std::string fullFileSpec = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "types_lua_default.xml"); llifstream file(fullFileSpec.c_str()); if (file.good()) -- cgit v1.3 From a0a59882c19f48d62459bf03ad28dfb7975e0dd0 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Fri, 6 Feb 2026 14:22:13 -0800 Subject: fetchKeywordsFileCoro would invoke loadKeywordsIntoLLSD as part of the coroutine. This would trigger an attempt to get a mutex which will fail in a coro. Instead post the cleanup back to the mainthread. --- indra/newview/llsyntaxid.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'indra/newview/llsyntaxid.cpp') diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index d9b2726992..16274f59bc 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -148,9 +148,14 @@ void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) if (isSupportedVersion(result)) { - setKeywordsXml(result); - cacheFile(fileSpec, result); - loadKeywordsIntoLLSD(); + // Shuttle this task to the main coro/worker. + // loadKeywordsIntoLLSD will attempt to get a mutex which is not coro aware. + LLAppViewer::instance()->postToMainCoro([this, result, fileSpec]() + { + setKeywordsXml(result); + cacheFile(fileSpec, result); + loadKeywordsIntoLLSD(); + }); } else { -- cgit v1.3