Updated multiple attachment code from Henri.
Signed-off-by: Beeks <HgDelirium@gmail.com>
This commit is contained in:
@@ -118,7 +118,7 @@ void dec_busy_count()
|
||||
|
||||
// Function declarations
|
||||
struct LLWearableHoldingPattern;
|
||||
void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append);
|
||||
void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace = FALSE);
|
||||
void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata);
|
||||
void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*);
|
||||
void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append);
|
||||
@@ -183,6 +183,7 @@ struct LLWearInfo
|
||||
{
|
||||
LLUUID mCategoryID;
|
||||
BOOL mAppend;
|
||||
BOOL mReplace;
|
||||
};
|
||||
|
||||
|
||||
@@ -2106,6 +2107,10 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model
|
||||
{
|
||||
modifyOutfit(TRUE);
|
||||
}
|
||||
else if ("wearitems" == action)
|
||||
{
|
||||
modifyOutfit(TRUE, TRUE);
|
||||
}
|
||||
else if ("removefromoutfit" == action)
|
||||
{
|
||||
// <edit> derf
|
||||
@@ -2495,6 +2500,7 @@ void LLFolderBridge::folderOptionsMenu()
|
||||
{
|
||||
// </edit>
|
||||
mItems.push_back(std::string("Add To Outfit"));
|
||||
mItems.push_back(std::string("Wear Items"));
|
||||
mItems.push_back(std::string("Replace Outfit"));
|
||||
// <edit>
|
||||
}
|
||||
@@ -2857,7 +2863,7 @@ void LLFolderBridge::createWearable(LLUUID parent_id, EWearableType type)
|
||||
LLPointer<LLInventoryCallback>(NULL));
|
||||
}
|
||||
|
||||
void LLFolderBridge::modifyOutfit(BOOL append)
|
||||
void LLFolderBridge::modifyOutfit(BOOL append, BOOL replace)
|
||||
{
|
||||
// <edit> derf
|
||||
if(std::find(LLInventoryPanel::sInstances.begin(), LLInventoryPanel::sInstances.end(), mInventoryPanel) == LLInventoryPanel::sInstances.end())
|
||||
@@ -2871,7 +2877,7 @@ void LLFolderBridge::modifyOutfit(BOOL append)
|
||||
LLViewerInventoryCategory* cat = getCategory();
|
||||
if(!cat) return;
|
||||
|
||||
wear_inventory_category_on_avatar( cat, append );
|
||||
wear_inventory_category_on_avatar(cat, append, replace);
|
||||
}
|
||||
|
||||
// helper stuff
|
||||
@@ -4791,7 +4797,7 @@ void wear_inventory_category(LLInventoryCategory* category, bool copy, bool appe
|
||||
}
|
||||
|
||||
// *NOTE: hack to get from avatar inventory to avatar
|
||||
void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL append )
|
||||
void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append, BOOL replace)
|
||||
{
|
||||
// Avoid unintentionally overwriting old wearables. We have to do
|
||||
// this up front to avoid having to deal with the case of multiple
|
||||
@@ -4802,6 +4808,7 @@ void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL appe
|
||||
|
||||
LLWearInfo* userdata = new LLWearInfo;
|
||||
userdata->mAppend = append;
|
||||
userdata->mReplace = replace;
|
||||
userdata->mCategoryID = category->getUUID();
|
||||
|
||||
if( gFloaterCustomize )
|
||||
@@ -4999,7 +5006,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata )
|
||||
msg->nextBlockFast(_PREHASH_ObjectData );
|
||||
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
|
||||
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, 0 | ATTACHMENT_ADD); // Wear at the previous or default attachment point
|
||||
msg->addU8Fast(_PREHASH_AttachmentPt, wear_info->mReplace ? 0 : ATTACHMENT_ADD); // Wear at the previous or default attachment point
|
||||
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
|
||||
msg->addStringFast(_PREHASH_Name, item->getName());
|
||||
msg->addStringFast(_PREHASH_Description, item->getDescription());
|
||||
|
||||
@@ -344,7 +344,7 @@ protected:
|
||||
|
||||
BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck);
|
||||
|
||||
void modifyOutfit(BOOL append);
|
||||
void modifyOutfit(BOOL append, BOOL replace = FALSE);
|
||||
public:
|
||||
static LLFolderBridge* sSelf;
|
||||
static void staticFolderOptionsMenu();
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "llaudioengine.h"
|
||||
#include "noise.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include "llagent.h" // Get state values from here
|
||||
#include "llviewercontrol.h"
|
||||
@@ -53,6 +54,7 @@
|
||||
|
||||
#include "llhudeffecttrail.h"
|
||||
#include "llhudmanager.h"
|
||||
#include "llinventorybridge.h"
|
||||
#include "llinventoryview.h"
|
||||
#include "llkeyframefallmotion.h"
|
||||
#include "llkeyframestandmotion.h"
|
||||
@@ -720,6 +722,10 @@ F32 LLVOAvatar::sGreyTime = 0.f;
|
||||
F32 LLVOAvatar::sGreyUpdateTime = 0.f;
|
||||
bool LLVOAvatar::sDoProperArc = true;
|
||||
|
||||
// Globals
|
||||
LLFrameTimer gAttachmentsTimer;
|
||||
bool gAttachmentsListDirty = true;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper functions
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -834,6 +840,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
|
||||
{
|
||||
mIsSelf = TRUE;
|
||||
gAgent.setAvatarObject(this);
|
||||
gAttachmentsTimer.reset();
|
||||
lldebugs << "Marking avatar as self " << id << llendl;
|
||||
}
|
||||
else
|
||||
@@ -2720,6 +2727,10 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
|
||||
|
||||
// attach objects that were waiting for a drawable
|
||||
lazyAttach();
|
||||
if (mIsSelf)
|
||||
{
|
||||
checkAttachments();
|
||||
}
|
||||
|
||||
// animate the character
|
||||
// store off last frame's root position to be consistent with camera position
|
||||
@@ -2756,6 +2767,133 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLVOAvatar::checkAttachments()
|
||||
{
|
||||
const F32 LAZY_ATTACH_DELAY = 15.0f;
|
||||
static bool first_run = true;
|
||||
|
||||
if (!mIsSelf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPendingAttachment.size() == 0)
|
||||
{
|
||||
if (first_run)
|
||||
{
|
||||
if (gAttachmentsTimer.getElapsedTimeF32() > LAZY_ATTACH_DELAY)
|
||||
{
|
||||
first_run = false;
|
||||
LLVOAvatar* avatarp = gAgent.getAvatarObject();
|
||||
if (!avatarp) return;
|
||||
std::set<LLUUID> worn;
|
||||
for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
|
||||
iter != avatarp->mAttachmentPoints.end(); )
|
||||
{
|
||||
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
|
||||
LLViewerJointAttachment* attachment = curiter->second;
|
||||
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
|
||||
attachment_iter != attachment->mAttachedObjects.end();
|
||||
++attachment_iter)
|
||||
{
|
||||
LLViewerObject *attached_object = (*attachment_iter);
|
||||
if (attached_object)
|
||||
{
|
||||
worn.insert(attached_object->getAttachmentItemID());
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "attachments.xml");
|
||||
//llinfos << "Reading the saved worn attachments list from: " << filename << llendl;
|
||||
LLSD list;
|
||||
llifstream llsd_xml;
|
||||
llsd_xml.open(filename.c_str(), std::ios::in | std::ios::binary);
|
||||
if (llsd_xml.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(list, llsd_xml);
|
||||
for (LLSD::map_iterator iter = list.beginMap(); iter != list.endMap(); iter++)
|
||||
{
|
||||
LLSD array = iter->second;
|
||||
if (array.isArray())
|
||||
{
|
||||
for (int i = 0; i < array.size(); i++)
|
||||
{
|
||||
LLSD map = array[i];
|
||||
if (map.has("inv_item_id"))
|
||||
{
|
||||
LLUUID item_id = map.get("inv_item_id");
|
||||
if (worn.find(item_id) == worn.end())
|
||||
{
|
||||
LLViewerInventoryItem* item = gInventory.getItem(item_id);
|
||||
if (item)
|
||||
{
|
||||
rez_attachment(item, NULL, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << item_id.asString() << " not found in inventory, could not reattach." << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Malformed attachments list file (no \"inv_item_id\" key). Aborting." << llendl;
|
||||
llsd_xml.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "Malformed attachments list file (not an array). Aborting." << llendl;
|
||||
llsd_xml.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
llsd_xml.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gAttachmentsListDirty)
|
||||
{
|
||||
gAttachmentsListDirty = false;
|
||||
LLSD list;
|
||||
LLSD array = list.emptyArray();
|
||||
LLVOAvatar* avatarp = gAgent.getAvatarObject();
|
||||
if (!avatarp) return;
|
||||
for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
|
||||
iter != avatarp->mAttachmentPoints.end(); )
|
||||
{
|
||||
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
|
||||
LLViewerJointAttachment* attachment = curiter->second;
|
||||
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
|
||||
attachment_iter != attachment->mAttachedObjects.end();
|
||||
++attachment_iter)
|
||||
{
|
||||
LLViewerObject *attached_object = (*attachment_iter);
|
||||
if (attached_object)
|
||||
{
|
||||
LLSD entry = list.emptyMap();
|
||||
entry.insert("inv_item_id", attached_object->getAttachmentItemID());
|
||||
array.append(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
list.insert("attachments", array);
|
||||
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "attachments.xml");
|
||||
llofstream list_file(filename);
|
||||
LLSDSerialize::toPrettyXML(list, list_file);
|
||||
list_file.close();
|
||||
//llinfos << "Worn attachments list saved to: " << filename << llendl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gAttachmentsListDirty = true;
|
||||
gAttachmentsTimer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
|
||||
{
|
||||
// disable voice visualizer when in mouselook
|
||||
@@ -3511,9 +3649,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
new_name = TRUE;
|
||||
}
|
||||
|
||||
LLNameValue *title = getNVPair("Title");
|
||||
LLNameValue* firstname = getNVPair("FirstName");
|
||||
LLNameValue* lastname = getNVPair("LastName");
|
||||
|
||||
// <edit>
|
||||
std::string client;
|
||||
@@ -3599,40 +3734,39 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
mClientTag = "Friend";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mIsSelf && gSavedSettings.getBOOL("AscentUseStatusColors"))
|
||||
{
|
||||
LLViewerRegion* parent_estate = LLWorld::getInstance()->getRegionFromPosGlobal(this->getPositionGlobal());
|
||||
LLUUID estate_owner = LLUUID::null;
|
||||
if(parent_estate && parent_estate->isAlive())
|
||||
if (!mIsSelf && gSavedSettings.getBOOL("AscentUseStatusColors"))
|
||||
{
|
||||
estate_owner = parent_estate->getOwner();
|
||||
}
|
||||
|
||||
std::string name;
|
||||
name += firstname->getString();
|
||||
name += " ";
|
||||
name += lastname->getString();
|
||||
//Lindens are always more Linden than your friend, make that take precedence
|
||||
if(LLMuteList::getInstance()->isLinden(name))
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentLindenColor").getValue();
|
||||
}
|
||||
//check if they are an estate owner at their current position
|
||||
else if(estate_owner.notNull() && this->getID() == estate_owner)
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentEstateOwnerColor").getValue();
|
||||
}
|
||||
//without these dots, SL would suck.
|
||||
else if (LLAvatarTracker::instance().getBuddyInfo(this->getID()) != NULL)
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentFriendColor");
|
||||
}
|
||||
//big fat jerkface who is probably a jerk, display them as such.
|
||||
else if(LLMuteList::getInstance()->isMuted(this->getID()))
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentMutedColor").getValue();
|
||||
LLViewerRegion* parent_estate = LLWorld::getInstance()->getRegionFromPosGlobal(this->getPositionGlobal());
|
||||
LLUUID estate_owner = LLUUID::null;
|
||||
if(parent_estate && parent_estate->isAlive())
|
||||
{
|
||||
estate_owner = parent_estate->getOwner();
|
||||
}
|
||||
/*this->getClientInfo
|
||||
std::string name;
|
||||
name += firstname->getString();
|
||||
name += " ";
|
||||
name += lastname->getString();
|
||||
//Lindens are always more Linden than your friend, make that take precedence
|
||||
if(LLMuteList::getInstance()->isLinden(name))
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentLindenColor").getValue();
|
||||
}*/
|
||||
//check if they are an estate owner at their current position
|
||||
else if(estate_owner.notNull() && this->getID() == estate_owner)
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentEstateOwnerColor").getValue();
|
||||
}
|
||||
//without these dots, SL would suck.
|
||||
else if (LLAvatarTracker::instance().getBuddyInfo(this->getID()) != NULL)
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentFriendColor");
|
||||
}
|
||||
//big fat jerkface who is probably a jerk, display them as such.
|
||||
else if(LLMuteList::getInstance()->isMuted(this->getID()))
|
||||
{
|
||||
mClientColor = LLSavedSettingsGlue::getCOAColor4("AscentMutedColor").getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3677,8 +3811,10 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
sNumVisibleChatBubbles--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LLNameValue *title = getNVPair("Title");
|
||||
LLNameValue* firstname = getNVPair("FirstName");
|
||||
LLNameValue* lastname = getNVPair("LastName");
|
||||
|
||||
if (mNameText.notNull() && firstname && lastname)
|
||||
{
|
||||
@@ -6965,12 +7101,22 @@ void LLVOAvatar::addChild(LLViewerObject *childp)
|
||||
{
|
||||
mPendingAttachment.push_back(childp);
|
||||
}
|
||||
if (mIsSelf)
|
||||
{
|
||||
gAttachmentsListDirty = true;
|
||||
gAttachmentsTimer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOAvatar::removeChild(LLViewerObject *childp)
|
||||
{
|
||||
LLViewerObject::removeChild(childp);
|
||||
detachObject(childp);
|
||||
if (mIsSelf)
|
||||
{
|
||||
gAttachmentsListDirty = true;
|
||||
gAttachmentsTimer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)
|
||||
@@ -7093,6 +7239,11 @@ void LLVOAvatar::lazyAttach()
|
||||
if (mPendingAttachment[i]->mDrawable)
|
||||
{
|
||||
attachObject(mPendingAttachment[i]);
|
||||
if (mIsSelf)
|
||||
{
|
||||
gAttachmentsListDirty = true;
|
||||
gAttachmentsTimer.reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7101,6 +7252,11 @@ void LLVOAvatar::lazyAttach()
|
||||
}
|
||||
|
||||
mPendingAttachment = still_pending;
|
||||
if (mIsSelf && still_pending.size() > 0)
|
||||
{
|
||||
gAttachmentsListDirty = true;
|
||||
gAttachmentsTimer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOAvatar::resetHUDAttachments()
|
||||
|
||||
@@ -301,6 +301,7 @@ public:
|
||||
BOOL attachObject(LLViewerObject *viewer_object);
|
||||
BOOL detachObject(LLViewerObject *viewer_object);
|
||||
void lazyAttach();
|
||||
void checkAttachments();
|
||||
|
||||
void sitOnObject(LLViewerObject *sit_object);
|
||||
void getOffObject();
|
||||
|
||||
@@ -208,6 +208,10 @@
|
||||
mouse_opaque="true" name="Add To Outfit" width="128">
|
||||
<on_click filter="" function="Inventory.DoToSelected" userdata="addtooutfit" />
|
||||
</menu_item_call>
|
||||
<menu_item_call bottom_delta="-18" height="18" label="Wear Items" left="0"
|
||||
mouse_opaque="true" name="Wear Items" width="128">
|
||||
<on_click filter="" function="Inventory.DoToSelected" userdata="wearitems" />
|
||||
</menu_item_call>
|
||||
<menu_item_call bottom_delta="-18" height="18" label="Replace Outfit" left="0"
|
||||
mouse_opaque="true" name="Replace Outfit" width="128">
|
||||
<on_click filter="" function="Inventory.DoToSelected" userdata="replaceoutfit" />
|
||||
|
||||
Reference in New Issue
Block a user