diff options
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/llappearancelistener.cpp | 110 | ||||
-rw-r--r-- | indra/newview/llappearancelistener.h | 44 | ||||
-rw-r--r-- | indra/newview/llappearancemgr.cpp | 28 | ||||
-rw-r--r-- | indra/newview/llappearancemgr.h | 2 | ||||
-rw-r--r-- | indra/newview/llviewermenu.cpp | 4 | ||||
-rw-r--r-- | indra/newview/scripts/lua/LLAppearance.lua | 25 | ||||
-rw-r--r-- | indra/newview/scripts/lua/luafloater_outfits_list.xml | 21 | ||||
-rw-r--r-- | indra/newview/scripts/lua/test_outfits_list.lua | 27 |
9 files changed, 255 insertions, 8 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ab65d71916..4e7e072289 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -95,6 +95,7 @@ set(viewer_SOURCE_FILES llagentwearables.cpp llanimstatelabels.cpp llappcorehttp.cpp + llappearancelistener.cpp llappearancemgr.cpp llappviewer.cpp llappviewerlistener.cpp @@ -760,6 +761,7 @@ set(viewer_HEADER_FILES llanimstatelabels.h llappcorehttp.h llappearance.h + llappearancelistener.h llappearancemgr.h llappviewer.h llappviewerlistener.h diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp new file mode 100644 index 0000000000..2d5ff6bee4 --- /dev/null +++ b/indra/newview/llappearancelistener.cpp @@ -0,0 +1,110 @@ +/** + * @file llappearancelistener.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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 "llappearancelistener.h" + +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "stringize.h" + +LLAppearanceListener::LLAppearanceListener() + : LLEventAPI("LLAppearance", + "API to wear a specified outfit and wear/remove individual items") +{ + add("wearOutfit", + "Wear outfit by folder id: [folder_id]" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfit, + llsd::map("folder_id", LLSD(), "append", LLSD())); + + add("wearOutfitByName", + "Wear outfit by folder name: [folder_name]" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfitByName, + llsd::map("folder_name", LLSD(), "append", LLSD())); + + add("getOutfitsList", + "Return the table of Outfits(id and name) which are send to the script", + &LLAppearanceListener::getOutfitsList); +} + + +void LLAppearanceListener::wearOutfit(LLSD const &data) +{ + Response response(LLSD(), data); + LLViewerInventoryCategory* cat = gInventory.getCategory(data["folder_id"].asUUID()); + if (!cat) + { + response.error(stringize("Couldn't find outfit ", data["folder_id"].asUUID())); + return; + } + if (LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + response.error(stringize("Can't wear system folder ", data["folder_id"].asUUID())); + return; + } + bool append = data["append"].asBoolean(); + bool can_wear = append ? LLAppearanceMgr::instance().getCanAddToCOF(cat->getUUID()) : LLAppearanceMgr::instance().getCanReplaceCOF(cat->getUUID()); + if (!can_wear) + { + std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + response.error(stringize(msg, std::quoted(cat->getName()), " , id: ", cat->getUUID())); + return; + } + LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); +} + +void LLAppearanceListener::wearOutfitByName(LLSD const &data) +{ + Response response(LLSD(), data); + std::string error_msg; + if (!LLAppearanceMgr::instance().wearOutfitByName(data["folder_name"].asString(), data["append"].asBoolean(), error_msg)) + { + response.error(error_msg); + } +} + +void LLAppearanceListener::getOutfitsList(LLSD const &data) +{ + Response response(LLSD(), data); + const LLUUID outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); + + LLSD outfits_data; + for (const LLPointer<LLViewerInventoryCategory> &cat : cat_array) + { + outfits_data[cat->getUUID().asString()] = cat->getName(); + } + response["outfits"] = outfits_data; +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h new file mode 100644 index 0000000000..8448b2ede9 --- /dev/null +++ b/indra/newview/llappearancelistener.h @@ -0,0 +1,44 @@ +/** + * @file llappearancelistener.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + + +#ifndef LL_LLAPPEARANCELISTENER_H +#define LL_LLAPPEARANCELISTENER_H + +#include "lleventapi.h" + +class LLAppearanceListener : public LLEventAPI +{ +public: + LLAppearanceListener(); + +private: + void wearOutfit(LLSD const &data); + void wearOutfitByName(LLSD const &data); + void getOutfitsList(LLSD const &data); +}; + +#endif // LL_LLAPPEARANCELISTENER_H + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 30f07a873b..19b81f5a79 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llappearancelistener.h" #include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llcommandhandler.h" @@ -71,6 +72,8 @@ #pragma warning (disable:4702) #endif +LLAppearanceListener sAppearanceListener; + namespace { const S32 BAKE_RETRY_MAX_COUNT = 5; @@ -2900,8 +2903,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } -// FIXME do we really want to search entire inventory for matching name? -void LLAppearanceMgr::wearOutfitByName(const std::string& name) +bool LLAppearanceMgr::wearOutfitByName(const std::string& name, bool append, std::string& error_msg) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; @@ -2936,13 +2938,29 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name) if(cat) { - LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false); + bool is_system_folder = LLFolderType::lookupIsProtectedType(cat->getPreferredType()); + if (is_system_folder) + { + error_msg = stringize("Can't wear system folder ", std::quoted(name)); + return false; + } + bool can_wear = append ? getCanAddToCOF(cat->getUUID()) : getCanReplaceCOF(cat->getUUID()); + if (!can_wear) + { + std::string msg = append ? "Can't add to COF outfit " : "Can't replace COF with outfit "; + error_msg = stringize(msg, std::quoted(name), " , id: ", cat->getUUID()); + LL_WARNS() << error_msg << LL_ENDL; + return false; + } + LLAppearanceMgr::wearInventoryCategory(cat, copy_items, append); } else { - LL_WARNS() << "Couldn't find outfit " <<name<< " in wearOutfitByName()" - << LL_ENDL; + error_msg = stringize("Couldn't find outfit ", std::quoted(name)); + LL_WARNS() << error_msg << LL_ENDL; + return false; } + return true; } bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index e5de92b653..d7b6cd5a61 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -59,7 +59,7 @@ public: void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); - void wearOutfitByName(const std::string& name); + bool wearOutfitByName(const std::string &name, bool append = false, std::string &error_msg = std::string()); void changeOutfit(bool proceed, const LLUUID& category, bool append); void replaceCurrentOutfit(const LLUUID& new_outfit); void renameOutfit(const LLUUID& outfit_id); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 90b7c43047..cea7180187 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9745,8 +9745,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedEnableAppearanceToXML(), "Advanced.EnableAppearanceToXML"); view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); - view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); - view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); + view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale", cb_info::UNTRUSTED_THROTTLE); + view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale", cb_info::UNTRUSTED_THROTTLE); // Advanced > Character > Animation Speed view_listener_t::addMenu(new LLAdvancedAnimTenFaster(), "Advanced.AnimTenFaster"); diff --git a/indra/newview/scripts/lua/LLAppearance.lua b/indra/newview/scripts/lua/LLAppearance.lua new file mode 100644 index 0000000000..ec7a25197f --- /dev/null +++ b/indra/newview/scripts/lua/LLAppearance.lua @@ -0,0 +1,25 @@ +leap = require 'leap' + +local LLAppearance = {} + +function LLAppearance.addOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = true, folder_id=folder}) +end + +function LLAppearance.replaceOutfit(folder) + leap.request('LLAppearance', {op='wearOutfit', append = false, folder_id=folder}) +end + +function LLAppearance.addOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = true, folder_name=folder}) +end + +function LLAppearance.replaceOutfitByName(folder) + leap.request('LLAppearance', {op='wearOutfitByName', append = false, folder_name=folder}) +end + +function LLAppearance.getOutfitsList() + return leap.request('LLAppearance', {op='getOutfitsList'})['outfits'] +end + +return LLAppearance diff --git a/indra/newview/scripts/lua/luafloater_outfits_list.xml b/indra/newview/scripts/lua/luafloater_outfits_list.xml new file mode 100644 index 0000000000..1f6505cb8d --- /dev/null +++ b/indra/newview/scripts/lua/luafloater_outfits_list.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="185" + layout="topleft" + name="lua_outfits" + title="Outfits" + width="320"> + <scroll_list + draw_heading="false" + left="5" + width="310" + height="150" + top_pad ="25" + follows="all" + name="outfits_list"> + <scroll_list.columns + name="outfit_name" + label="Name"/> + </scroll_list> +</floater> diff --git a/indra/newview/scripts/lua/test_outfits_list.lua b/indra/newview/scripts/lua/test_outfits_list.lua new file mode 100644 index 0000000000..5875fd51da --- /dev/null +++ b/indra/newview/scripts/lua/test_outfits_list.lua @@ -0,0 +1,27 @@ +local Floater = require 'Floater' +local LLAppearance = require 'LLAppearance' +local startup = require 'startup' + +local flt = Floater:new( + "luafloater_outfits_list.xml", + {outfits_list = {"double_click"}}) + +function flt:post_build(event_data) + local outfits_map = LLAppearance.getOutfitsList() + local action_data = {} + action_data.action = "add_list_element" + action_data.ctrl_name = "outfits_list" + local outfits = {} + for uuid, name in pairs(outfits_map) do + table.insert(outfits, {value = uuid, columns={column = "outfit_name", value = name}}) + end + action_data.value = outfits + self:post(action_data) +end + +function flt:double_click_outfits_list(event_data) + LLAppearance.replaceOutfit(event_data.value) +end + +startup.wait('STATE_STARTED') +flt:show() |