diff options
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
-rw-r--r-- | indra/newview/rlvdefines.h | 1 | ||||
-rw-r--r-- | indra/newview/rlvfloaters.cpp | 95 | ||||
-rw-r--r-- | indra/newview/rlvfloaters.h | 40 | ||||
-rw-r--r-- | indra/newview/rlvhandler.cpp | 6 | ||||
-rw-r--r-- | indra/newview/rlvhandler.h | 15 | ||||
-rw-r--r-- | indra/newview/rlvhelper.cpp | 38 | ||||
-rw-r--r-- | indra/newview/rlvhelper.h | 5 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_rlv_console.xml | 73 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 5 |
11 files changed, 255 insertions, 27 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a7bbadfd86..e3f675cb8e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -728,6 +728,7 @@ set(viewer_SOURCE_FILES pipeline.cpp rlvactions.cpp rlvcommon.cpp + rlvfloaters.cpp rlvhelper.cpp rlvhandler.cpp ) @@ -1393,6 +1394,7 @@ set(viewer_HEADER_FILES rlvdefines.h rlvactions.h rlvcommon.h + rlvfloaters.h rlvhelper.h rlvhandler.h roles_constants.h diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 9bdd246129..e41d8c44fb 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -175,6 +175,7 @@ #include "llpreviewtexture.h" #include "llscriptfloater.h" #include "llsyswellwindow.h" +#include "rlvfloaters.h" // *NOTE: Please add files in alphabetical order to keep merges easy. @@ -480,6 +481,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); + LLFloaterReg::add("rlv_console", "floater_rlv_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<Rlv::FloaterConsole>); LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index c36512007b..88dffa1127 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -52,6 +52,7 @@ namespace Rlv namespace Constants { constexpr char CmdPrefix = '@'; + constexpr char ConsolePrompt[] = "> "; constexpr std::string_view OptionSeparator = ";"; } } diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp new file mode 100644 index 0000000000..8d107b2540 --- /dev/null +++ b/indra/newview/rlvfloaters.cpp @@ -0,0 +1,95 @@ +#include "llviewerprecompiledheaders.h" + +#include "llagentdata.h" +#include "llchatentry.h" +#include "lltexteditor.h" +#include "lltrans.h" +#include "llvoavatarself.h" + +#include "rlvfloaters.h" +#include "rlvhandler.h" + +using namespace Rlv; + +// ============================================================================ +// FloaterConsole +// + +bool FloaterConsole::postBuild() +{ + mInputEdit = getChild<LLChatEntry>("console_input"); + mInputEdit->setCommitCallback(std::bind(&FloaterConsole::onInput, this)); + mInputEdit->setTextExpandedCallback(std::bind(&FloaterConsole::reshapeLayoutPanel, this)); + mInputEdit->setFocus(true); + mInputEdit->setCommitOnFocusLost(false); + + mInputPanel = getChild<LLLayoutPanel>("input_panel"); + mInputEditPad = mInputPanel->getRect().getHeight() - mInputEdit->getRect().getHeight(); + + mOutputText = getChild<LLTextEditor>("console_output"); + mOutputText->appendText(Constants::ConsolePrompt, false); + + if (RlvHandler::isEnabled()) + { + mCommandOutputConn = RlvHandler::instance().setCommandOutputCallback([this](const RlvCommand& rlvCmd, S32, const std::string strText) + { + if (rlvCmd.getObjectID() == gAgentID) + { + mOutputText->appendText(rlvCmd.getBehaviour() + ": ", true); + mOutputText->appendText(strText, false); + } + }); + } + + return true; +} + +void FloaterConsole::onClose(bool fQuitting) +{ + if (RlvHandler::isEnabled()) + { + RlvHandler::instance().processCommand(gAgentID, "clear", true); + } +} + +void FloaterConsole::onInput() +{ + if (!isAgentAvatarValid()) + { + return; + } + + std::string strText = mInputEdit->getText(); + LLStringUtil::trim(strText); + + mOutputText->appendText(strText, false); + mInputEdit->setText(LLStringUtil::null); + + if (!RlvHandler::isEnabled()) + { + mOutputText->appendText(LLTrans::getString("RlvConsoleDisable"), true); + } + else if (strText.length() <= 3 || Constants::CmdPrefix != strText[0]) + { + mOutputText->appendText(LLTrans::getString("RlvConsoleInvalidCmd"), true); + } + else + { + LLChat chat; + chat.mFromID = gAgentID; + chat.mChatType = CHAT_TYPE_OWNER; + + RlvHandler::instance().handleSimulatorChat(strText, chat, gAgentAvatarp); + + mOutputText->appendText(strText, true); + } + + mOutputText->appendText(Constants::ConsolePrompt, true); +} + +void FloaterConsole::reshapeLayoutPanel() +{ + mInputPanel->reshape(mInputPanel->getRect().getWidth(), mInputEdit->getRect().getHeight() + mInputEditPad, false); +} + +// ============================================================================ diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h new file mode 100644 index 0000000000..a599bb051a --- /dev/null +++ b/indra/newview/rlvfloaters.h @@ -0,0 +1,40 @@ +#pragma once + +#include "llfloater.h" + +#include "rlvdefines.h" + +class LLChatEntry; +class LLLayoutPanel; +class LLTextEditor; +class RlvCommand; +class RlvHandler; + +namespace Rlv +{ + // ============================================================================ + // FloaterConsole - debug console to allow command execution without the need for a script + // + + class FloaterConsole : public LLFloater + { + friend class LLFloaterReg; + FloaterConsole(const LLSD& sdKey) : LLFloater(sdKey) {} + + public: + bool postBuild() override; + void onClose(bool fQuitting) override; + protected: + void onInput(); + void reshapeLayoutPanel(); + + private: + boost::signals2::scoped_connection mCommandOutputConn; + int mInputEditPad = 0; + LLLayoutPanel* mInputPanel = nullptr; + LLChatEntry* mInputEdit = nullptr; + LLTextEditor* mOutputText = nullptr; + }; + + // ============================================================================ +}; diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 8b2620cf48..0a0da0e25d 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1,6 +1,5 @@ #include "llviewerprecompiledheaders.h" #include "llagent.h" -#include "llappviewer.h" #include "llstartup.h" #include "llviewercontrol.h" #include "llviewerobject.h" @@ -38,7 +37,7 @@ bool RlvHandler::handleSimulatorChat(std::string& message, const LLChat& chat, c message.erase(0, 1); LLStringUtil::toLower(message); - CommandDbgOut cmdDbgOut(message); + CommandDbgOut cmdDbgOut(message, chatObj->getID() == gAgentID); boost_tokenizer tokens(message, boost::char_separator<char>(",", "", boost::drop_empty_tokens)); for (const std::string& strCmd : tokens) @@ -128,7 +127,7 @@ ECmdRet CommandHandlerBaseImpl<EParamType::Reply>::processCommand(const RlvComma { // Sanity check - <param> should specify a - valid - reply channel S32 nChannel; - if (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel) || !Util::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) + if (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel) || !Util::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgentID)) return ECmdRet::FailedParam; std::string strReply; @@ -141,6 +140,7 @@ ECmdRet CommandHandlerBaseImpl<EParamType::Reply>::processCommand(const RlvComma { Util::sendChatReply(nChannel, strReply); } + RlvHandler::instance().mOnCommandOutput(rlvCmd, nChannel, strReply); return eRet; } diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h index a5e91548ef..7fa4da767a 100644 --- a/indra/newview/rlvhandler.h +++ b/indra/newview/rlvhandler.h @@ -13,6 +13,8 @@ class LLViewerObject; class RlvHandler : public LLSingleton<RlvHandler> { + template<Rlv::EParamType> friend struct Rlv::CommandHandlerBaseImpl; + LLSINGLETON_EMPTY_CTOR(RlvHandler); /* @@ -25,12 +27,25 @@ public: protected: Rlv::ECmdRet processCommand(std::reference_wrapper<const RlvCommand> rlvCmdRef, bool fromObj); + /* + * Helper functions + */ public: // Initialization (deliberately static so they can safely be called in tight loops) static bool canEnable(); static bool isEnabled() { return mIsEnabled; } static bool setEnabled(bool enable); + /* + * Event handling + */ +public: + // The command output signal is triggered whenever a command produces channel or debug output + using command_output_signal_t = boost::signals2::signal<void (const RlvCommand&, S32, const std::string&)>; + boost::signals2::connection setCommandOutputCallback(const command_output_signal_t::slot_type& cb) { return mOnCommandOutput.connect(cb); } + +protected: + command_output_signal_t mOnCommandOutput; private: static bool mIsEnabled; }; diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index aad615d813..ecb76a1db3 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -250,21 +250,13 @@ namespace Rlv void CommandDbgOut::add(std::string strCmd, ECmdRet eRet) { - ECmdRet resultBucket; - - // Successful and retained commands are added as-is - if (isReturnCodeSuccess(eRet)) - resultBucket = ECmdRet::Success; - else if (ECmdRet::Retained == eRet) - resultBucket = ECmdRet::Retained; - else - { - // Failed commands get the failure reason appended to help troubleshooting - resultBucket = ECmdRet::Failed; - strCmd.append(llformat(" (%s)", getReturnCodeString(eRet).c_str())); - } + const std::string strSuffix = getReturnCodeString(eRet); + if (!strSuffix.empty()) + strCmd.append(llformat(" (%s)", strSuffix.c_str())); + else if (mForConsole) + return; // Only show console feedback on successful commands when there's an informational notice - std::string& strResult = mCommandResults[resultBucket]; + std::string& strResult = mCommandResults[isReturnCodeSuccess(eRet) ? ECmdRet::Success : (ECmdRet::Retained == eRet ? ECmdRet::Retained : ECmdRet::Failed)]; if (!strResult.empty()) strResult.append(", "); strResult.append(strCmd); @@ -273,23 +265,25 @@ namespace Rlv std::string CommandDbgOut::get() const { std::ostringstream result; - if (1 == mCommandResults.size()) + if (1 == mCommandResults.size() && !mForConsole) { auto it = mCommandResults.begin(); - result << " " << getDebugVerbFromReturnCode(it->first) << ": @" << it->second;; + result << " " << getDebugVerbFromReturnCode(it->first) << ": @" << it->second; } - else if (mCommandResults.size() > 1) + else if (!mCommandResults.empty()) { auto appendResult = [&](ECmdRet eRet, const std::string& name) { auto it = mCommandResults.find(eRet); if (it == mCommandResults.end()) return; - result << "\n - " << LLTrans::getString(name) << ": @" << it->second; + if (!mForConsole) result << "\n - "; + result << LLTrans::getString(name) << ": @" << it->second; }; - result << ": @" << mOrigCmd; - appendResult(ECmdRet::Success, "RlvDebugExecuted"); - appendResult(ECmdRet::Failed, "RlvDebugFailed"); - appendResult(ECmdRet::Retained, "RlvDebugRetained"); + if (!mForConsole) + result << ": @" << mOrigCmd; + appendResult(ECmdRet::Success, !mForConsole ? "RlvDebugExecuted" : "RlvConsoleExecuted"); + appendResult(ECmdRet::Failed, !mForConsole ? "RlvDebugFailed" : "RlvConsoleFailed"); + appendResult(ECmdRet::Retained, !mForConsole ? "RlvDebugRetained" : "RlvConsoleRetained"); } return result.str(); diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index 802b1cbadd..644cd0ee22 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -141,7 +141,7 @@ namespace Rlv template<EBehaviour templBhvr> using ForceHandler = CommandHandler<EParamType::Force, templBhvr>; template<EBehaviour templBhvr> using ReplyHandler = CommandHandler<EParamType::Reply, templBhvr>; - // List of shared handlers + // List of shared handlers using VersionReplyHandler = ReplyHandler<EBehaviour::Version>; // Shared between @version and @versionnew // @@ -192,7 +192,7 @@ namespace Rlv struct CommandDbgOut { - CommandDbgOut(const std::string& orig_cmd) : mOrigCmd(orig_cmd) {} + CommandDbgOut(const std::string& orig_cmd, bool for_console) : mOrigCmd(orig_cmd), mForConsole(for_console) {} void add(std::string strCmd, ECmdRet eRet); std::string get() const; static std::string getDebugVerbFromReturnCode(ECmdRet eRet); @@ -200,6 +200,7 @@ namespace Rlv private: std::string mOrigCmd; std::map<ECmdRet, std::string> mCommandResults; + bool mForConsole = false; }; } diff --git a/indra/newview/skins/default/xui/en/floater_rlv_console.xml b/indra/newview/skins/default/xui/en/floater_rlv_console.xml new file mode 100644 index 0000000000..928d50cb41 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_console.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_resize="true" + height="400" + layout="topleft" + min_height="300" + min_width="300" + name="rlv_console" + title="RLVa console" + width="600" + > + <layout_stack + animate="false" + bottom="-1" + default_tab_group="2" + follows="all" + left="5" + layout="topleft" + mouse_opaque="false" + name="main_stack" + right="-5" + orientation="vertical" + tab_group="1" + top="1" + > + <layout_panel + name="body_panel" + height="235"> + <text_editor + follows="all" + left="1" + right="-1" + top="0" + length="1" + font="Monospace" + bottom="-1" + ignore_tab="false" + layout="topleft" + max_length="65536" + name="console_output" + read_only="true" + track_end="true" + type="string" + word_wrap="true" + > + </text_editor> + </layout_panel> + + <layout_panel + height="26" + auto_resize="false" + name="input_panel"> + <chat_editor + layout="topleft" + expand_lines_count="5" + follows="left|right|bottom" + font="SansSerifSmall" + height="20" + is_expandable="true" + text_tentative_color="TextFgTentativeColor" + name="console_input" + max_length="1023" + spellcheck="true" + tab_group="3" + bottom_delta="20" + left="1" + top="1" + right="-1" + wrap="true" + /> + </layout_panel> + </layout_stack> +</floater> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 39a663298a..cebe1ff6c3 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -4377,6 +4377,11 @@ and report the problem. </string> <!-- RLVa --> + <string name="RlvConsoleDisable">RLVa is disabled</string> + <string name="RlvConsoleInvalidCmd">Invalid command</string> + <string name="RlvConsoleExecuted">INFO</string> + <string name="RlvConsoleFailed">ERR</string> + <string name="RlvConsoleRetained">RET</string> <string name="RlvDebugExecuted">executed</string> <string name="RlvDebugFailed">failed</string> <string name="RlvDebugRetained">retained</string> |