#3857 second batch of new or updated LEAP functions

meow-7.2.2
Mnikolenko Productengine 2025-04-03 12:34:51 +03:00
parent db2c45ba23
commit 46fca6f5bb
12 changed files with 350 additions and 51 deletions

View File

@ -553,6 +553,61 @@ LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter
} // namespace llsd
/*****************************************************************************
* toArray(), toMap()
*****************************************************************************/
namespace llsd
{
// For some T convertible to LLSD, given std::vector<T> myVec,
// toArray(myVec) returns an LLSD array whose entries correspond to the
// items in myVec.
// For some U convertible to LLSD, given function U xform(const T&),
// toArray(myVec, xform) returns an LLSD array whose every entry is
// xform(item) of the corresponding item in myVec.
// toArray() actually works with any container<C> usable with range
// 'for', not just std::vector.
// (Once we get C++20 we can use std::identity instead of this default lambda.)
template<typename C, typename FUNC>
LLSD toArray(const C& container, FUNC&& func = [](const auto& arg) { return arg; })
{
LLSD array;
for (const auto& item : container)
{
array.append(std::forward<FUNC>(func)(item));
}
return array;
}
// For some T convertible to LLSD, given std::map<std::string, T> myMap,
// toMap(myMap) returns an LLSD map whose entries correspond to the
// (key, value) pairs in myMap.
// For some U convertible to LLSD, given function
// std::pair<std::string, U> xform(const std::pair<std::string, T>&),
// toMap(myMap, xform) returns an LLSD map whose every entry is
// xform(pair) of the corresponding (key, value) pair in myMap.
// toMap() actually works with any container usable with range 'for', not
// just std::map. It need not even be an associative container, as long as
// you pass an xform function that returns std::pair<std::string, U>.
// (Once we get C++20 we can use std::identity instead of this default lambda.)
template<typename C, typename FUNC>
LLSD toMap(const C& container, FUNC&& func = [](const auto& arg) { return arg; })
{
LLSD map;
for (const auto& pair : container)
{
const auto& [key, value] = std::forward<FUNC>(func)(pair);
map[key] = value;
}
return map;
}
} // namespace llsd
/*****************************************************************************
* boost::hash<LLSD>
*****************************************************************************/
// Specialization for generating a hash value from an LLSD block.
namespace boost
{

View File

@ -92,6 +92,7 @@ set(viewer_SOURCE_FILES
llagentwearables.cpp
llanimstatelabels.cpp
llappcorehttp.cpp
llappearancelistener.cpp
llappearancemgr.cpp
llappviewer.cpp
llappviewerlistener.cpp
@ -761,6 +762,7 @@ set(viewer_HEADER_FILES
llanimstatelabels.h
llappcorehttp.h
llappearance.h
llappearancelistener.h
llappearancemgr.h
llappviewer.h
llappviewerlistener.h

View File

@ -2,11 +2,11 @@
* @file groupchatlistener.cpp
* @author Nat Goodspeed
* @date 2011-04-11
* @brief Implementation for groupchatlistener.
* @brief Implementation for LLGroupChatListener.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
* 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
@ -34,43 +34,69 @@
// std headers
// external library headers
// other Linden headers
#include "llchat.h"
#include "llgroupactions.h"
#include "llimview.h"
namespace {
void startIm_wrapper(LLSD const & event)
{
LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID());
sendReply(LLSDMap("session_id", LLSD(session_id)), event);
}
void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id)
{
LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START);
}
}
GroupChatListener::GroupChatListener():
LLGroupChatListener::LLGroupChatListener():
LLEventAPI("GroupChat",
"API to enter, leave, send and intercept group chat messages")
{
add("startIM",
"Enter a group chat in group with UUID [\"id\"]\n"
add("startGroupChat",
"Enter a group chat in group with UUID [\"group_id\"]\n"
"Assumes the logged-in agent is already a member of this group.",
&startIm_wrapper);
add("endIM",
"Leave a group chat in group with UUID [\"id\"]\n"
&LLGroupChatListener::startGroupChat,
llsd::map("group_id", LLSD()));
add("leaveGroupChat",
"Leave a group chat in group with UUID [\"group_id\"]\n"
"Assumes a prior successful startIM request.",
&LLGroupActions::endIM,
llsd::array("id"));
add("sendIM",
"send a groupchat IM",
&send_message_wrapper,
llsd::array("text", "session_id", "group_id"));
&LLGroupChatListener::leaveGroupChat,
llsd::map("group_id", LLSD()));
add("sendGroupIM",
"send a [\"message\"] to group with UUID [\"group_id\"]",
&LLGroupChatListener::sendGroupIM,
llsd::map("message", LLSD(), "group_id", LLSD()));
}
bool is_in_group(LLEventAPI::Response &response, const LLSD &data)
{
if (!LLGroupActions::isInGroup(data["group_id"]))
{
response.error(stringize("You are not the member of the group:", std::quoted(data["group_id"].asString())));
return false;
}
return true;
}
void LLGroupChatListener::startGroupChat(LLSD const &data)
{
Response response(LLSD(), data);
if (!is_in_group(response, data))
{
return;
}
if (LLGroupActions::startIM(data["group_id"]).isNull())
{
return response.error(stringize("Failed to start group chat session ", std::quoted(data["group_id"].asString())));
}
}
void LLGroupChatListener::leaveGroupChat(LLSD const &data)
{
Response response(LLSD(), data);
if (is_in_group(response, data))
{
LLGroupActions::endIM(data["group_id"].asUUID());
}
}
void LLGroupChatListener::sendGroupIM(LLSD const &data)
{
Response response(LLSD(), data);
if (!is_in_group(response, data))
{
return;
}
LLUUID group_id(data["group_id"]);
LLIMModel::sendMessage(data["message"], gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), group_id, IM_SESSION_SEND);
}
/*
static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id,
const LLUUID& other_participant_id, EInstantMessage dialog);
*/

View File

@ -26,15 +26,20 @@
* $/LicenseInfo$
*/
#if ! defined(LL_GROUPCHATLISTENER_H)
#define LL_GROUPCHATLISTENER_H
#if ! defined(LL_LLGROUPCHATLISTENER_H)
#define LL_LLGROUPCHATLISTENER_H
#include "lleventapi.h"
class GroupChatListener: public LLEventAPI
class LLGroupChatListener: public LLEventAPI
{
public:
GroupChatListener();
LLGroupChatListener();
private:
void startGroupChat(LLSD const &data);
void leaveGroupChat(LLSD const &data);
void sendGroupIM(LLSD const &data);
};
#endif /* ! defined(LL_GROUPCHATLISTENER_H) */
#endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */

View File

@ -62,7 +62,6 @@ private:
void removeFollowCamParams(LLSD const & event_data) const;
void playAnimation(LLSD const &event_data);
void playAnimation_(const LLUUID& asset_id, const bool inworld);
void stopAnimation(LLSD const &event_data);
void getAnimationInfo(LLSD const &event_data);

View File

@ -0,0 +1,158 @@
/**
* @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 "lltransutil.h"
#include "llwearableitemslist.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\"] OR by folder name: [\"folder_name\"]\n"
"When [\"append\"] is true, outfit will be added to COF\n"
"otherwise it will replace current oufit",
&LLAppearanceListener::wearOutfit);
add("wearItems",
"Wear items by id: [items_id]",
&LLAppearanceListener::wearItems,
llsd::map("items_id", LLSD(), "replace", LLSD()));
add("detachItems",
"Detach items by id: [items_id]",
&LLAppearanceListener::detachItems,
llsd::map("items_id", LLSD()));
add("getOutfitsList",
"Return the table with Outfits info(id and name)",
&LLAppearanceListener::getOutfitsList);
add("getOutfitItems",
"Return the table of items with info(id : name, wearable_type, is_worn) inside specified outfit folder",
&LLAppearanceListener::getOutfitItems);
}
void LLAppearanceListener::wearOutfit(LLSD const &data)
{
Response response(LLSD(), data);
if (!data.has("folder_id") && !data.has("folder_name"))
{
return response.error("Either [folder_id] or [folder_name] is required");
}
bool append = data.has("append") ? data["append"].asBoolean() : false;
if (!LLAppearanceMgr::instance().wearOutfit(data, append))
{
response.error("Failed to wear outfit");
}
}
void LLAppearanceListener::wearItems(LLSD const &data)
{
const LLSD& items_id{ data["items_id"] };
uuid_vec_t ids;
if (!items_id.isArray())
{
ids.push_back(items_id.asUUID());
}
else // array
{
for (const auto& id : llsd::inArray(items_id))
{
ids.push_back(id);
}
}
LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean());
}
void LLAppearanceListener::detachItems(LLSD const &data)
{
const LLSD& items_id{ data["items_id"] };
uuid_vec_t ids;
if (!items_id.isArray())
{
ids.push_back(items_id.asUUID());
}
else // array
{
for (const auto& id : llsd::inArray(items_id))
{
ids.push_back(id);
}
}
LLAppearanceMgr::instance().removeItemsFromAvatar(ids);
}
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);
response["outfits"] = llsd::toMap(cat_array,
[](const LLPointer<LLViewerInventoryCategory> &cat)
{ return std::make_pair(cat->getUUID().asString(), cat->getName()); });
}
void LLAppearanceListener::getOutfitItems(LLSD const &data)
{
Response response(LLSD(), data);
LLUUID outfit_id(data["outfit_id"].asUUID());
LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id);
if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT)
{
return response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString()));
}
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
LLFindOutfitItems collector = LLFindOutfitItems();
gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector);
response["items"] = llsd::toMap(item_array,
[](const LLPointer<LLViewerInventoryItem> &it)
{
return std::make_pair(
it->getUUID().asString(),
llsd::map(
"name", it->getName(),
"wearable_type", LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE),
"is_worn", get_is_item_worn(it)));
});
}

View File

@ -0,0 +1,46 @@
/**
* @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 wearItems(LLSD const &data);
void detachItems(LLSD const &data);
void getOutfitsList(LLSD const &data);
void getOutfitItems(LLSD const &data);
};
#endif // LL_LLAPPEARANCELISTENER_H

View File

@ -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"
@ -66,6 +67,8 @@
#include "llavatarpropertiesprocessor.h"
LLAppearanceListener sAppearanceListener;
namespace
{
const S32 BAKE_RETRY_MAX_COUNT = 5;
@ -4762,6 +4765,11 @@ bool wear_category(const LLSD& query_map, bool append)
return false;
}
bool LLAppearanceMgr::wearOutfit(const LLSD& query_map, bool append)
{
return wear_category(query_map, append);
}
class LLWearFolderHandler : public LLCommandHandler
{
public:

View File

@ -60,6 +60,7 @@ public:
void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append);
void wearOutfitByName(const std::string& name);
bool wearOutfit(const LLSD& query_map, bool append = false);
void changeOutfit(bool proceed, const LLUUID& category, bool append);
void replaceCurrentOutfit(const LLUUID& new_outfit);
void renameOutfit(const LLUUID& outfit_id);

View File

@ -46,7 +46,7 @@
//
// Globals
//
static GroupChatListener sGroupChatListener;
static LLGroupChatListener sGroupChatListener;
class LLGroupHandler : public LLCommandHandler
{

View File

@ -33,7 +33,6 @@
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
#include "llinventoryicon.h"
#include "llgesturemgr.h"
#include "lltransutil.h"
@ -41,15 +40,6 @@
#include "llviewermenu.h"
#include "llvoavatarself.h"
class LLFindOutfitItems : public LLInventoryCollectFunctor
{
public:
LLFindOutfitItems() {}
virtual ~LLFindOutfitItems() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{

View File

@ -32,6 +32,7 @@
#include "llsingleton.h"
// newview
#include "llinventoryfunctions.h"
#include "llinventoryitemslist.h"
#include "llinventorylistitem.h"
#include "lllistcontextmenu.h"
@ -507,4 +508,12 @@ protected:
LLWearableType::EType mMenuWearableType;
};
class LLFindOutfitItems : public LLInventoryCollectFunctor
{
public:
LLFindOutfitItems() {}
virtual ~LLFindOutfitItems() {}
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
};
#endif //LL_LLWEARABLEITEMSLIST_H