diff options
| author | Rider Linden <rider@lindenlab.com> | 2025-10-01 15:30:40 -0700 |
|---|---|---|
| committer | Rider Linden <rider@lindenlab.com> | 2025-10-07 09:19:42 -0700 |
| commit | 339e7ccae99aab39a01aef052719ab9b3432919b (patch) | |
| tree | f9298aae9ae88afa9afb885899c2bfa26af64b11 | |
| parent | 672bdc8915bc5f7f305b6b51751e2c0578ef6032 (diff) | |
Added scripting options floater for config, switched to using config values. Added "runtime.debug" and "runtime.error" notifications.
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 44 | ||||
| -rw-r--r-- | indra/newview/llfloaterimnearbychathandler.cpp | 11 | ||||
| -rw-r--r-- | indra/newview/llfloaterpreference.cpp | 6 | ||||
| -rw-r--r-- | indra/newview/llfloaterpreference.h | 1 | ||||
| -rw-r--r-- | indra/newview/llfloaterscripting.cpp | 106 | ||||
| -rw-r--r-- | indra/newview/llfloaterscripting.h | 49 | ||||
| -rw-r--r-- | indra/newview/llpreviewscript.cpp | 19 | ||||
| -rw-r--r-- | indra/newview/llscripteditorws.cpp | 162 | ||||
| -rw-r--r-- | indra/newview/llscripteditorws.h | 26 | ||||
| -rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_scripting_settings.xml | 143 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_advanced.xml | 51 |
13 files changed, 561 insertions, 61 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6c7b4fef81..702a738e57 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -291,6 +291,7 @@ set(viewer_SOURCE_FILES llfloatersceneloadstats.cpp llfloaterscriptdebug.cpp llfloaterscriptedprefs.cpp + llfloaterscripting.cpp llfloaterscriptlimits.cpp llfloatersearch.cpp llfloatersellland.cpp @@ -971,6 +972,7 @@ set(viewer_HEADER_FILES llfloatersceneloadstats.h llfloaterscriptdebug.h llfloaterscriptedprefs.h + llfloaterscripting.h llfloaterscriptlimits.h llfloatersearch.h llfloatersellland.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8d2e077f0b..3f4800ac91 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13915,6 +13915,50 @@ <key>Value</key> <string /> </map> + <key>ExternalWebsocketSyncEnable</key> + <map> + <key>Comment</key> + <string>Enables the Websocket JSONRPC server when doing external script editing.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>ExternalWebsocketSyncPort</key> + <map> + <key>Comment</key> + <string>Port that the JSONRPC server listens on when editing</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>9020</integer> + </map> + <key>ExternalWebsocketSyncLocal</key> + <map> + <key>Comment</key> + <string>Should the JSONRPC server listen only for local connections.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>ExternalWebsocketForwardDebug</key> + <map> + <key>Comment</key> + <string>Forward messages and runtime errors for a script to JSONRPC client.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>YawFromMousePosition</key> <map> <key>Comment</key> diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index c920a3c898..1e3bc2804e 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -44,6 +44,7 @@ #include "llfloaterimcontainer.h" #include "llrootview.h" #include "lllayoutstack.h" +#include "llscripteditorws.h" //add LLFloaterIMNearbyChatHandler to LLNotificationsUI namespace using namespace LLNotificationsUI; @@ -335,6 +336,7 @@ void LLFloaterIMNearbyChatScreenChannel::addChat(LLSD& chat) { if (!gSavedSettings.getBOOL("ShowScriptErrors")) return; + if (gSavedSettings.getS32("ShowScriptErrorsLocation") == 1) return; } @@ -526,6 +528,15 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, if (!gSavedSettings.getBOOL("ShowScriptErrors")) return; + if (gSavedSettings.getBOOL("ExternalWebsocketSyncEnable") && gSavedSettings.getBOOL("ExternalWebsocketForwardDebug")) + { + LLScriptEditorWSServer::ptr_t server = LLScriptEditorWSServer::getServer(); + if (server) + { + server->forwardChatToIDE(chat_msg); + } + } + // don't process debug messages from not owned objects, see EXT-7762 if (gAgentID != chat_msg.mOwnerID) { diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 291f22d78f..1f13a2f933 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -346,6 +346,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); + mCommitCallbackRegistrar.add("Pref.Scripting", boost::bind(&LLFloaterPreference::onClickScriptingPerfs, this)); sSkin = gSavedSettings.getString("SkinCurrent"); @@ -1825,6 +1826,11 @@ void LLFloaterPreference::onClickAdvanced() } } +void LLFloaterPreference::onClickScriptingPerfs() +{ + LLFloaterReg::showInstance("scripting_settings"); +} + void LLFloaterPreference::onClickActionChange() { updateClickActionControls(); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index a784d502ef..73abe49d22 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -190,6 +190,7 @@ public: void onClickRenderExceptions(); void onClickAutoAdjustments(); void onClickAdvanced(); + void onClickScriptingPerfs(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); void onLogChatHistorySaved(); diff --git a/indra/newview/llfloaterscripting.cpp b/indra/newview/llfloaterscripting.cpp new file mode 100644 index 0000000000..0719ced58d --- /dev/null +++ b/indra/newview/llfloaterscripting.cpp @@ -0,0 +1,106 @@ +/** + * @file llfloaterscripting.cpp + * @brief Asset creation permission preferences. + * @author Jonathan Yap + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2025, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llcheckboxctrl.h" +#include "llfloaterscripting.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "lluictrlfactory.h" +#include "llpermissions.h" +#include "llagent.h" +#include "llviewerregion.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" +#include "llvoavatar.h" +#include "llcorehttputil.h" +#include "lleventfilter.h" +#include "lleventcoro.h" +#include "llviewermenufile.h" +#include "llappviewer.h" + +namespace +{ + class LLEditorPicker : public LLFilePickerThread + { + public: + LLEditorPicker(LLFloaterScripting *floater): + LLFilePickerThread(LLFilePicker::FFLOAD_EXE) + { + mHandle = floater->getDerivedHandle<LLFloaterScripting>(); + } + void notify(const std::vector<std::string>& filenames) override + { + if (LLAppViewer::instance()->quitRequested()) + { + return; + } + + LLFloaterScripting* floater = mHandle.get(); + if (floater && !filenames.empty()) + { + floater->pickedEditor(filenames.front()); + } + } + + private: + LLHandle<LLFloaterScripting> mHandle; + }; + +} + +LLFloaterScripting::LLFloaterScripting(const LLSD& seed) + : LLFloater(seed) +{ + mCommitCallbackRegistrar.add("ScriptingSettings.CLOSE", boost::bind(&LLFloaterScripting::onClickClose, this)); + mCommitCallbackRegistrar.add("ScriptingSettings.BROWSE", boost::bind(&LLFloaterScripting::onClickBrowse, this)); +} + +bool LLFloaterScripting::postBuild() +{ + refresh(); + return true; +} + +void LLFloaterScripting::onClickClose() +{ + closeFloater(); +} + +void LLFloaterScripting::onClickBrowse() +{ + (new LLEditorPicker(this))->getFile(); +} + +void LLFloaterScripting::pickedEditor(std::string_view editor) +{ + assert_main_thread(); + std::stringstream cmdline; + cmdline << "\"" << editor << "\" \"%s\""; + + gSavedSettings.setString("ExternalEditor", cmdline.str()); +} diff --git a/indra/newview/llfloaterscripting.h b/indra/newview/llfloaterscripting.h new file mode 100644 index 0000000000..ca7bd3e091 --- /dev/null +++ b/indra/newview/llfloaterscripting.h @@ -0,0 +1,49 @@ +/** + * @file llfloaterscripting.h + * @brief Asset creation permission preferences. + * @author Jonathan Yap + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2025, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "llfloater.h" +#include "lleventcoro.h" +#include "llcoros.h" + +class LLFloaterScripting : public LLFloater +{ + friend class LLFloaterReg; + +public: + bool postBuild() override; + void onClickClose(); + void onClickBrowse(); + + void pickedEditor(std::string_view editor); + +private: + LLFloaterScripting(const LLSD& seed); + +}; + diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 9aac1742d5..bd1f68da33 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1671,27 +1671,26 @@ bool LLScriptEdContainer::handleKeyHere(KEY key, MASK mask) void LLScriptEdContainer::startWebsocketServer() { - // if the user has enabled websockets, create the server to talk to the external editor + if (gSavedSettings.getBOOL("ExternalWebsocketSyncEnable")) { - // TODO: Get the name, port, and locality from settings - std::string server_name(LLScriptEditorWSServer::DEFAULT_SERVER_NAME); - 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<LLScriptEditorWSServer>(wsmgr.findServerByName(server_name)); + LLScriptEditorWSServer::ptr_t server = + std::static_pointer_cast<LLScriptEditorWSServer>( + wsmgr.findServerByName(LLScriptEditorWSServer::DEFAULT_SERVER_NAME)); if (!server) { // We couldn't find one, so create it - server = std::make_shared<LLScriptEditorWSServer>(server_name, server_port, server_localhost); + U16 server_port = static_cast<U16>(gSavedSettings.getS32("ExternalWebsocketSyncPort")); + bool server_localhost = gSavedSettings.getBOOL("ExternalWebsocketSyncLocal"); + server = std::make_shared<LLScriptEditorWSServer>(LLScriptEditorWSServer::DEFAULT_SERVER_NAME, server_port, server_localhost); wsmgr.addServer(server); } bool is_running = server->isRunning(); if (!is_running) { // Server isn't running, so start it - is_running = wsmgr.startServer(server_name); + is_running = wsmgr.startServer(LLScriptEditorWSServer::DEFAULT_SERVER_NAME); } if (!is_running && !server->isRunning()) @@ -1701,7 +1700,7 @@ void LLScriptEdContainer::startWebsocketServer() } std::string script_id_hash_str(getUniqueHash()); - server->subscribeScriptEditor(getHandle(), script_id_hash_str); + server->subscribeScriptEditor(mObjectUUID, mItemUUID, mScriptEd->mScriptName, getHandle(), script_id_hash_str); mWebSocketServer = server; } } diff --git a/indra/newview/llscripteditorws.cpp b/indra/newview/llscripteditorws.cpp index 2df4c73cd9..72aaf919ea 100644 --- a/indra/newview/llscripteditorws.cpp +++ b/indra/newview/llscripteditorws.cpp @@ -35,6 +35,9 @@ #include "llversioninfo.h" #include "llagent.h" #include "llregex.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llchat.h" //======================================================================== LLScriptEditorWSServer::LLScriptEditorWSServer(const std::string& name, U16 port, bool local_only) @@ -44,6 +47,18 @@ LLScriptEditorWSServer::LLScriptEditorWSServer(const std::string& name, U16 port << " on port " << port << LL_ENDL; } +LLScriptEditorWSServer::ptr_t LLScriptEditorWSServer::getServer() +{ + if (!LLWebsocketMgr::instanceExists()) + { + return nullptr; + } + LLWebsocketMgr& wsmgr = LLWebsocketMgr::instance(); + return std::static_pointer_cast<LLScriptEditorWSServer>( + wsmgr.findServerByName(LLScriptEditorWSServer::DEFAULT_SERVER_NAME)); +} + + LLWebsocketMgr::WSConnection::ptr_t LLScriptEditorWSServer::connectionFactory(LLWebsocketMgr::WSServer::ptr_t server, LLWebsocketMgr::connection_h handle) { @@ -109,14 +124,16 @@ void LLScriptEditorWSServer::onConnectionClosed(const LLWebsocketMgr::WSConnecti } } -bool LLScriptEditorWSServer::subscribeScriptEditor(const LLHandle<LLPanel>& editor_handle, const std::string &script_id) +bool LLScriptEditorWSServer::subscribeScriptEditor(const LLUUID& object_id, const LLUUID& item_id, std::string_view script_name, + const LLHandle<LLPanel>& editor_handle, const std::string& script_id) { if (!editor_handle.isDead()) { 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() }); + { // Don't re-add if already subscribed + mSubscriptions.emplace(script_id, + LLScriptEditorWSServer::EditorSubscription(object_id, item_id, script_name, editor_handle)); return false; } else @@ -369,8 +386,14 @@ LLSD LLScriptEditorWSServer::handleScriptSubscribe(U32 connection_id, const LLSD if (result == SUBSCRIPTION_SUCCESS) { - //TODO: Build an info block for the subscribed script. - //buildScriptSubscriptionInfo(result); + auto it = mSubscriptions.find(script_id); + if (it != mSubscriptions.end()) + { + LLViewerObject* object = gObjectList.findObject((*it).second.mObjectID); + response["object_id"] = (*it).second.mObjectID; + //response["object_name"] = object ? object->getName() : "Unknown"; + response["item_id"] = (*it).second.mItemID; + } } return response; @@ -499,6 +522,133 @@ void LLScriptEditorWSServer::sendCompileResults(const std::string &script_id, co notifyScript(script_id, "script.compiled", params); } +void LLScriptEditorWSServer::forwardChatToIDE(const LLChat& chat_msg) const +{ + auto it = std::find_if(mSubscriptions.begin(), mSubscriptions.end(), + [&chat_msg](const auto& pair) { return (pair.second.mObjectID == chat_msg.mFromID); }); + + if (it == mSubscriptions.end()) + { // Not a script we are tracking + return; + } + + bool is_error = false; + std::string error_message; + std::string object_name; + std::string script_name; + S32 line_number = 0; + // We have at least one script from this object, we will forward the message to the IDE + // but first we need to see if it is a runtime error + std::vector<std::string> lines = LLStringUtil::getTokens(chat_msg.mText, "\n"); + // If this is a runtime error, the first line will look like: "<Object Name> [script:<Script Name>] Script run-time error" + static const std::string runtime_error_marker = "Script run-time error"; + if (!lines.empty() && std::equal(runtime_error_marker.rbegin(), runtime_error_marker.rend(), lines.front().rbegin())) + { + is_error = true; + std::string first_line = lines.front(); + + // Extract the object and script name from the first line + static const boost::regex RUNTIME_ERR_REGEX_FLEX(R"(^(.+?)\s+\[script:([^\]]+)\]\s+Script run-time error)"); + boost::smatch m; + + S32 remove_count = 0; + if (boost::regex_match(first_line, m, RUNTIME_ERR_REGEX_FLEX)) + { + object_name = m[1].str(); + script_name = m[2].str(); + remove_count++; + } + + // TODO: Build an actual error message to forward to the external editor + // Explaination: + // Well! Heck! + // As it turns out, the complete error message arrives as either two or three + // separate chat messages from the server. + // 2 if the script is LSL or if it is Lua but not owned by the editing agent + // 3 if the script is Lua and owned by the editing agent. + // + // Message 1: <Object Name> [script:<Script Name>] Script run-time error + // Message 2: <runtime error> + // Message 3: <script>:<line>: <actual error message>\n + // <call stack> + // + // These need to be compositited into a single error message to send to the IDE. + // + //if (lines.size() > 1) + //{ // The second line is the actual error message + // error_message = lines[1]; + // remove_count++; + // if ((error_message == "runtime error") && (lines.size() > 2)) + // { // If the error message is just "runtime error", the next line might actually be the real message: + // // "lua_script:7: attempt to perform arithmetic (sub) on nil" + // static const boost::regex LUA_ERROR_REGEX(R"(^(.+?):(\d+):\s*(.+)$)"); + // + // if (boost::regex_match(first_line, m, RUNTIME_ERR_REGEX_FLEX)) + // { + // line_number = std::stoi(m[2].str()); + // error_message = m[3].str(); + // remove_count++; + // } + // } + // else + // { + // error_message = "Unknown script runtime error"; + // } + //} + //else + //{ + // error_message = "Unknown script runtime error"; + //} + if (lines.size() > remove_count) + { // The rest of the lines may contain a stack trace + lines.erase(lines.begin(), lines.begin() + remove_count); + } + else + { + lines.clear(); + } + + // We should also check that the script name matches one of our subscriptions + if (!script_name.empty() && (it->second.mScriptName != script_name)) + { // right object, wrong script + auto sit = std::find_if(mSubscriptions.begin(), mSubscriptions.end(), + [&chat_msg, &script_name](const auto& pair) + { + return (pair.second.mScriptName == script_name) && (pair.second.mObjectID == chat_msg.mFromID); + }); + if (sit != mSubscriptions.end()) + { // We have a better match + it = sit; + } + } + } + std::string script_id = it->first; + LLSD message; + message["scriptId"] = script_id; + message["objectId"] = chat_msg.mFromID; + message["objectName"] = chat_msg.mFromName; + message["message"] = chat_msg.mText; + + if (is_error) + { + message["error"] = error_message; + message["line"] = line_number; + if (!lines.empty()) + { + message["stack"] = LLSD::emptyArray(); + for (const auto& line : lines) + { + message["stack"].append(line); + } + } + } + + if (!it->second.mConnection.expired()) + { + it->second.mConnection.lock()->notify(is_error ? "runtime.error" : "runtime.debug", message); + } +} + //======================================================================== U32 LLScriptEditorWSConnection::sNextConnectionID = 1; @@ -522,7 +672,7 @@ void LLScriptEditorWSConnection::onOpen() handshake["viewer_version"] = LLVersionInfo::instance().getVersion(); handshake["agent_id"] = gAgent.getID(); - handshake["agent_name"] = "todo"; + handshake["agent_name"] = gAgentUsername; std::string challenge_file = generateChallenge(); if (!challenge_file.empty()) diff --git a/indra/newview/llscripteditorws.h b/indra/newview/llscripteditorws.h index 2c3ae31e8d..3ed23a0b7e 100644 --- a/indra/newview/llscripteditorws.h +++ b/indra/newview/llscripteditorws.h @@ -41,6 +41,8 @@ class LLLiveLSLEditor; class LLScriptEdContainer; class LLScriptEditorWSServer; +class LLChat; +class LLPanel; class LLScriptEditorWSConnection : public LLJSONRPCConnection, public std::enable_shared_from_this<LLScriptEditorWSConnection> { @@ -159,12 +161,15 @@ public: virtual ~LLScriptEditorWSServer() = default; + static LLScriptEditorWSServer::ptr_t getServer(); + 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 subscribeScriptEditor(const LLHandle<LLPanel>& editor_handle, const std::string &script_id); + bool subscribeScriptEditor(const LLUUID& object_id, const LLUUID& item_id, std::string_view script_name, + const LLHandle<LLPanel>& editor_handle, const std::string &script_id); void unsubscribeEditor(const std::string &script_id); void notifyScript(const std::string& script_id, const std::string& method, const LLSD& message) const; @@ -173,10 +178,8 @@ public: LLHandle<LLPanel> findEditorForScript(const std::string& script_id) const; - /** - * @brief Get list of active script editing sessions - * @return Set of script IDs currently being edited - */ + void forwardChatToIDE(const LLChat& chat_msg) const; + std::set<std::string> getActiveScripts() const; protected: @@ -195,9 +198,18 @@ protected: private: struct EditorSubscription { - LLHandle<LLPanel> mEditorHandle; - LLScriptEditorWSConnection::wptr_t mConnection; + EditorSubscription(const LLUUID &object_id, const LLUUID &item_id, std::string_view script_name, LLHandle<LLPanel> editor_handle): + mObjectID(object_id), + mItemID(item_id), + mScriptName(script_name), + mEditorHandle(editor_handle) + {} U32 mConnectionID{ 0 }; + LLUUID mObjectID; + LLUUID mItemID; + std::string mScriptName; + LLScriptEditorWSConnection::wptr_t mConnection; + LLHandle<LLPanel> mEditorHandle; }; using subscriptions_t = std::unordered_map<std::string, EditorSubscription>; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 3b35ca8db1..107b3df831 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -132,6 +132,7 @@ #include "llfloatersavecamerapreset.h" #include "llfloatersaveprefpreset.h" #include "llfloatersceneloadstats.h" +#include "llfloaterscripting.h" #include "llfloaterscriptdebug.h" #include "llfloaterscriptedprefs.h" #include "llfloaterscriptlimits.h" @@ -492,6 +493,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>); LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptLimits>); + LLFloaterReg::add("scripting_settings", "floater_scripting_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScripting>); LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyScripts>); LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); LLFloaterReg::add("settings_color", "floater_settings_color.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSettingsColor>); diff --git a/indra/newview/skins/default/xui/en/floater_scripting_settings.xml b/indra/newview/skins/default/xui/en/floater_scripting_settings.xml new file mode 100644 index 0000000000..fb782a20d1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_scripting_settings.xml @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<floater + legacy_header_height="18" + height="265" + layout="topleft" + name="floater_scripting_settings" + help_topic="scripting_settings" + save_rect="true" + title="SCRIPT DEVELOPMENT SETTINGS" + width="485"> + <check_box + control_name="ShowScriptErrors" + follows="left|top" + height="20" + label="Show script errors in:" + layout="topleft" + left="30" + top_pad="20" + name="show_script_errors" + width="256" /> + <radio_group + enabled_control="ShowScriptErrors" + control_name="ShowScriptErrorsLocation" + follows="top|left" + height="16" + layout="topleft" + left_delta="50" + name="show_location" + top_pad="5" + width="364"> + <radio_item + height="16" + label="Nearby chat" + layout="topleft" + left="3" + name="0" + top="0" + width="315" /> + <radio_item + height="16" + label="Separate window" + layout="topleft" + left_delta="175" + name="1" + top_delta="0" + width="315" /> + </radio_group> + + <text + follows="top|left|right" + height="15" + layout="topleft" + left="30" + name="tip" + top_pad="20" + width="330" + wrap="true"> + External Script Editor: + </text> + <line_editor + control_name="ExternalEditor" + follows="top|left" + height="20" + initial_value="" + layout="left" + left_pad="5" + name="external_editor" + top_delta="25" + value="" + width="360" /> + <button + follows="left|top" + height="20" + label="Browse..." + layout="topleft" + left_pad="5" + name="browse_btn" + top_delta="0" + width="70"> + <button.commit_callback + function="ScriptingSettings.BROWSE" /> + </button> + + <check_box + control_name="ExternalWebsocketSyncEnable" + follows="top|left" + height="20" + label="Enable WebScocket Sync" + layout="topleft" + left="30" + name="websocket_sync_enable" + top_pad="20" + width="200" /> + + <text + enabled_control="ExternalWebsocketSyncEnable" + follows="top|left" + height="15" + layout="topleft" + left="50" + name="websocket_tip" + top_pad="10" + width="140" + wrap="false"> + WebSocket Listen Port: + </text> + <line_editor + enabled_control="ExternalWebsocketSyncEnable" + control_name="ExternalWebsocketSyncPort" + follows="top|left" + height="20" + initial_value="9020" + layout="topleft" + left_pad="5" + name="websocket_port" + top_delta="-2" + value="9020" + width="120" /> + <check_box + control_name="ExternalWebsocketForwardDebug" + enabled_control="ExternalWebsocketSyncEnable" + follows="top|left" + height="20" + label="Forward script errors and debug to WebSocket clients" + layout="topleft" + left="50" + name="websocket_forward_debug" + top_pad="5" + width="400" /> + + <button + follows="left|top" + height="23" + label="Close" + layout="topleft" + right="-10" + name="close_btn" + top="-30" + width="100"> + <button.commit_callback + function="ScriptingSettings.CLOSE" /> + </button> +</floater> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 86999b1afb..434ee1db35 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -169,43 +169,6 @@ name="hud_scale_slider" top_pad="-14" width="250" /> - <check_box - control_name="ShowScriptErrors" - follows="left|top" - height="20" - label="Show script errors in:" - layout="topleft" - left="30" - top_pad="10" - name="show_script_errors" - width="256" /> - <radio_group - enabled_control="ShowScriptErrors" - control_name="ShowScriptErrorsLocation" - follows="top|left" - height="16" - layout="topleft" - left_delta="50" - name="show_location" - top_pad="5" - width="364"> - <radio_item - height="16" - label="Nearby chat" - layout="topleft" - left="3" - name="0" - top="0" - width="315" /> - <radio_item - height="16" - label="Separate window" - layout="topleft" - left_delta="175" - name="1" - top_delta="0" - width="315" /> - </radio_group> <check_box control_name="AllowMultipleViewers" @@ -266,9 +229,21 @@ name="default_creation_permissions" height="20" left="30" - top_pad="16" + top_pad="10" width="200"> <button.commit_callback function="Pref.PermsDefault" /> </button> + <button + follows="top|left" + layout="topleft" + label="Script Development" + name="scripting_development" + height="20" + left="30" + top_pad="10" + width="200"> + <button.commit_callback + function="Pref.Scripting" /> + </button> </panel> |
