THE BIGGIE.

Holy hell, this was an interesting one to implement. I wish I understood it better. Unfortunately I think this marks the end of trying to re-implement the Local Inventory for Temp and Local textures. It's just not feasible now that the entire inventory system has been whipped into a code shitstorm.

Signed-off-by: Beeks <HgDelirium@gmail.com>
This commit is contained in:
Beeks
2010-09-22 06:48:48 -04:00
parent 3d4fee4614
commit ec55705bdd
48 changed files with 8559 additions and 7177 deletions

View File

@@ -253,6 +253,10 @@ const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
// group constants
const S32 MAX_AGENT_GROUPS = 25;
// attachment constants
const S32 MAX_AGENT_ATTACHMENTS = 38;
const U8 ATTACHMENT_ADD = 0x80;
// god levels
const U8 GOD_MAINTENANCE = 250;
const U8 GOD_FULL = 200;

View File

@@ -70,6 +70,8 @@ asset_info_t asset_types[] =
{ LLAssetType::AT_ANIMATION, "ANIMATION" },
{ LLAssetType::AT_GESTURE, "GESTURE" },
{ LLAssetType::AT_SIMSTATE, "SIMSTATE" },
{ LLAssetType::AT_LINK, "LINK" },
{ LLAssetType::AT_LINK_FOLDER, "FOLDER_LINK" },
{ LLAssetType::AT_NONE, "NONE" },
};
@@ -129,7 +131,10 @@ const char* LLAssetType::mAssetTypeNames[LLAssetType::AT_COUNT] =
"jpeg",
"animatn",
"gesture",
"simstate"
"simstate",
"",
"link",
"link_f"
};
// This table is meant for decoding to human readable form. Put any
@@ -159,7 +164,10 @@ const char* LLAssetType::mAssetTypeHumanNames[LLAssetType::AT_COUNT] =
"jpeg image",
"animation",
"gesture",
"simstate"
"simstate",
"",
"symbolic link",
"symbolic folder link"
};
///----------------------------------------------------------------------------
@@ -248,6 +256,7 @@ EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
case AT_BODYPART: return DAD_BODYPART;
case AT_ANIMATION: return DAD_ANIMATION;
case AT_GESTURE: return DAD_GESTURE;
case AT_LINK: return DAD_LINK;
default: return DAD_NONE;
};
}
@@ -265,3 +274,16 @@ void LLAssetType::generateDescriptionFor(LLAssetType::EType type,
desc.assign(time_str);
desc.append(LLAssetType::lookupHumanReadable(type));
}
// static
bool LLAssetType::lookupCanLink(EType asset_type)
{
return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);
}
// static
// Not adding this to dictionary since we probably will only have these two types
bool LLAssetType::lookupIsLinkType(EType asset_type)
{
return (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER);
}

View File

@@ -131,6 +131,12 @@ public:
// simstate file
AT_SIMSTATE = 22,
// Inventory symbolic link
AT_LINK = 24,
// Inventory folder link
AT_LINK_FOLDER = 25,
// +*********************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
// +*********************************************+
@@ -140,7 +146,7 @@ public:
// | 4. ADD TO LLAssetType::mAssetTypeHumanNames |
// +*********************************************+
AT_COUNT = 23,
AT_COUNT = 26,
AT_NONE = -1
};
@@ -164,6 +170,9 @@ public:
static EType getType(const std::string& sin);
static std::string getDesc(EType type);
static bool lookupCanLink(EType asset_type);
static bool lookupIsLinkType(EType asset_type);
private:
// don't instantiate or derive one of these objects

View File

@@ -54,7 +54,8 @@ enum EDragAndDropType
DAD_BODYPART = 11,
DAD_ANIMATION = 12,
DAD_GESTURE = 13,
DAD_COUNT = 14, // number of types in this enum
DAD_LINK = 14,
DAD_COUNT = 15, // number of types in this enum
};
// Reasons for drags to be denied.

View File

@@ -126,6 +126,25 @@ const std::string& LLInventoryObject::getName() const
return mName;
}
// To bypass linked items, since llviewerinventory's getType
// will return the linked-to item's type instead of this object's type.
LLAssetType::EType LLInventoryObject::getActualType() const
{
return mType;
}
BOOL LLInventoryObject::getIsLinkType() const
{
return LLAssetType::lookupIsLinkType(mType);
}
// See LLInventoryItem override.
// virtual
const LLUUID& LLInventoryObject::getLinkedUUID() const
{
return mUUID;
}
LLAssetType::EType LLInventoryObject::getType() const
{
return mType;
@@ -342,6 +361,19 @@ void LLInventoryItem::cloneItem(LLPointer<LLInventoryItem>& newitem) const
newitem->mUUID.generate();
}
// If this is a linked item, then the UUID of the base object is
// this item's assetID.
// virtual
const LLUUID& LLInventoryItem::getLinkedUUID() const
{
if (LLAssetType::lookupIsLinkType(getActualType()))
{
return mAssetUUID;
}
return LLInventoryObject::getLinkedUUID();
}
const LLPermissions& LLInventoryItem::getPermissions() const
{
return mPermissions;

View File

@@ -89,14 +89,17 @@ public:
void copyObject(const LLInventoryObject* other); // LLRefCount requires custom copy
// accessors
const LLUUID& getUUID() const;
virtual const LLUUID& getUUID() const;
const LLUUID& getParentUUID() const;
const std::string& getName() const;
LLAssetType::EType getType() const;
virtual const LLUUID& getLinkedUUID() const; // get the inventoryID that this item points to, else this item's inventoryID
virtual const std::string& getName() const;
virtual LLAssetType::EType getType() const;
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
BOOL getIsLinkType() const;
// mutators - will not call updateServer();
void setUUID(const LLUUID& new_uuid);
void rename(const std::string& new_name);
virtual void rename(const std::string& new_name);
void setParent(const LLUUID& new_parent);
void setType(LLAssetType::EType type);
@@ -231,15 +234,16 @@ public:
virtual void cloneItem(LLPointer<LLInventoryItem>& newitem) const;
// accessors
const LLPermissions& getPermissions() const;
const LLUUID& getCreatorUUID() const;
const LLUUID& getAssetUUID() const;
const std::string& getDescription() const;
const LLSaleInfo& getSaleInfo() const;
LLInventoryType::EType getInventoryType() const;
U32 getFlags() const;
time_t getCreationDate() const;
U32 getCRC32() const; // really more of a checksum.
virtual const LLUUID& getLinkedUUID() const;
virtual const LLPermissions& getPermissions() const;
virtual const LLUUID& getCreatorUUID() const;
virtual const LLUUID& getAssetUUID() const;
virtual const std::string& getDescription() const;
virtual const LLSaleInfo& getSaleInfo() const;
virtual LLInventoryType::EType getInventoryType() const;
virtual U32 getFlags() const;
virtual time_t getCreationDate() const;
virtual U32 getCRC32() const; // really more of a checksum.
// mutators - will not call updateServer(), and will never fail
// (though it may correct to sane values)

View File

@@ -120,6 +120,10 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // AT_IMAGE_JPEG
LLInventoryType::IT_ANIMATION, // AT_ANIMATION
LLInventoryType::IT_GESTURE, // AT_GESTURE
LLInventoryType::IT_NONE, // AT_SIMSTATE
LLInventoryType::IT_NONE, // (null entry)
LLInventoryType::IT_NONE, // AT_LINK
LLInventoryType::IT_NONE, // AT_LINK_FOLDER
};
static const int MAX_POSSIBLE_ASSET_TYPES = 2;

View File

@@ -292,6 +292,8 @@ bool is_asset_id_knowable(LLAssetType::EType type)
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_ANIMATION:
case LLAssetType::AT_GESTURE:
case LLAssetType::AT_LINK:
case LLAssetType::AT_LINK_FOLDER:
rv = true;
break;
default:

View File

@@ -174,6 +174,7 @@ char* _PREHASH_UpdateInventoryItem = LLMessageStringTable::getInstance()->getStr
char* _PREHASH_UpdateCreateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateCreateInventoryItem");
char* _PREHASH_MoveInventoryItem = LLMessageStringTable::getInstance()->getString("MoveInventoryItem");
char* _PREHASH_CopyInventoryItem = LLMessageStringTable::getInstance()->getString("CopyInventoryItem");
char* _PREHASH_LinkInventoryItem = LLMessageStringTable::getInstance()->getString("LinkInventoryItem");
char* _PREHASH_RemoveInventoryItem = LLMessageStringTable::getInstance()->getString("RemoveInventoryItem");
char* _PREHASH_CreateInventoryItem = LLMessageStringTable::getInstance()->getString("CreateInventoryItem");
char* _PREHASH_PathTwistBegin = LLMessageStringTable::getInstance()->getString("PathTwistBegin");

View File

@@ -174,6 +174,7 @@ extern char * _PREHASH_UpdateInventoryItem;
extern char * _PREHASH_UpdateCreateInventoryItem;
extern char * _PREHASH_MoveInventoryItem;
extern char * _PREHASH_CopyInventoryItem;
extern char * _PREHASH_LinkInventoryItem;
extern char * _PREHASH_RemoveInventoryItem;
extern char * _PREHASH_CreateInventoryItem;
extern char * _PREHASH_PathTwistBegin;

View File

@@ -2,6 +2,44 @@
<llsd>
<map>
<!--Expanded settings from Vanilla SL -->
<key>BeauchampUseInventoryLinks</key>
<map>
<key>Comment</key>
<string>When making a new outfit, use links for no-copy items</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>MoyFastMiniMap</key>
<map>
<key>Comment</key>
<string>When making a new outfit, use links for no-copy items</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>MoyMiniMapCustomColor</key>
<map>
<key>Comment</key>
<string>Custom minimap color you wish to have.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Color4</string>
<key>Value</key>
<array>
<real>0.375</real>
<real>1.0</real>
<real>1.0</real>
<real>1.0</real>
</array>
</map>
<key>ShyotlRenderUseStreamVBO</key>
<map>
<key>Comment</key>

View File

@@ -79,6 +79,7 @@ private:
LLColor4 mLindenColor;
LLColor4 mMutedColor;
LLColor4 mEMColor;
LLColor4 mCustomColor;
U32 mSelectedClient;
};
@@ -213,6 +214,7 @@ void LLPrefsAscentVanImpl::refreshValues()
mLindenColor = LLSavedSettingsGlue::getCOAColor4("AscentLindenColor");
mMutedColor = LLSavedSettingsGlue::getCOAColor4("AscentMutedColor");
mEMColor = LLSavedSettingsGlue::getCOAColor4("AscentEstateOwnerColor");
mCustomColor = LLSavedSettingsGlue::getCOAColor4("MoyMiniMapCustomColor");
}
void LLPrefsAscentVanImpl::refresh()
@@ -236,6 +238,7 @@ void LLPrefsAscentVanImpl::refresh()
getChild<LLColorSwatchCtrl>("linden_color_swatch")->set(mLindenColor);
getChild<LLColorSwatchCtrl>("muted_color_swatch")->set(mMutedColor);
getChild<LLColorSwatchCtrl>("em_color_swatch")->set(mEMColor);
getChild<LLColorSwatchCtrl>("custom_color_swatch")->set(mCustomColor);
LLSavedSettingsGlue::setCOAColor4("EffectColor", LLColor4::white);
LLSavedSettingsGlue::setCOAColor4("EffectColor", mEffectColor);
@@ -250,6 +253,9 @@ void LLPrefsAscentVanImpl::refresh()
LLSavedSettingsGlue::setCOAColor4("AscentEstateOwnerColor", LLColor4::white);
LLSavedSettingsGlue::setCOAColor4("AscentEstateOwnerColor", mEMColor);
LLSavedSettingsGlue::setCOAColor4("MoyMiniMapCustomColor", LLColor4::white);
LLSavedSettingsGlue::setCOAColor4("MoyMiniMapCustomColor", mCustomColor);
gAgent.resetClientTag();
}
@@ -268,6 +274,8 @@ void LLPrefsAscentVanImpl::cancel()
LLSavedSettingsGlue::setCOAColor4("AscentMutedColor", mMutedColor);
LLSavedSettingsGlue::setCOAColor4("AscentEstateOwnerColor", LLColor4::yellow);
LLSavedSettingsGlue::setCOAColor4("AscentEstateOwnerColor", mEMColor);
LLSavedSettingsGlue::setCOAColor4("MoyMiniMapCustomColor", LLColor4::yellow);
LLSavedSettingsGlue::setCOAColor4("MoyMiniMapCustomColor", mCustomColor);
}
void LLPrefsAscentVanImpl::apply()
@@ -304,6 +312,7 @@ void LLPrefsAscentVanImpl::apply()
LLSavedSettingsGlue::setCOAColor4("AscentLindenColor", childGetValue("linden_color_swatch"));
LLSavedSettingsGlue::setCOAColor4("AscentMutedColor", childGetValue("muted_color_swatch"));
LLSavedSettingsGlue::setCOAColor4("AscentEstateOwnerColor", childGetValue("em_color_swatch"));
LLSavedSettingsGlue::setCOAColor4("MoyMiniMapCustomColor", childGetValue("custom_color_swatch"));
LLSavedSettingsGlue::setCOABOOL("AscentUseCustomTag", childGetValue("customize_own_tag_check"));
LLSavedSettingsGlue::setCOAString("AscentCustomTagLabel", childGetValue("custom_tag_label_box"));
LLSavedSettingsGlue::setCOAColor4("AscentCustomTagColor", childGetValue("custom_tag_color_swatch"));

View File

@@ -3463,13 +3463,18 @@ void LLAgent::updateCamera()
{
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
LLViewerObject *attached_object = attachment->getObject();
if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull())
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
// clear any existing "early" movements of attachment
attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE);
gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
attached_object->updateText();
LLViewerObject *attached_object = (*attachment_iter);
if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull())
{
// clear any existing "early" movements of attachment
attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE);
gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
attached_object->updateText();
}
}
}
@@ -6633,7 +6638,15 @@ void LLAgent::sendAgentWearablesUpdate()
if( wearable )
{
LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << mWearableEntry[ i ].mItemID << LL_ENDL;
gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID );
LLUUID item_id = mWearableEntry[i].mItemID;
const LLViewerInventoryItem *item = gInventory.getItem(item_id);
if (item && item->getIsLinkType())
{
// Get the itemID that this item points to. i.e. make sure
// we are storing baseitems, not their links, in the database.
item_id = item->getLinkedUUID();
}
gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
}
else
{
@@ -6942,7 +6955,8 @@ BOOL LLAgent::selfHasWearable( void* userdata )
BOOL LLAgent::isWearingItem( const LLUUID& item_id )
{
return (getWearableFromWearableItem( item_id ) != NULL);
const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
return (getWearableFromWearableItem(base_item_id) != NULL);
}
// static
@@ -7246,6 +7260,7 @@ void LLAgent::makeNewOutfit(
new_folder_name);
bool found_first_item = false;
BOOL no_link = !gSavedSettings.getBOOL("BeauchampUseInventoryLinks");
///////////////////
// Wearables
@@ -7255,7 +7270,6 @@ void LLAgent::makeNewOutfit(
// Then, iterate though each of the wearables and save copies of them in the folder.
S32 i;
S32 count = wearables_to_include.count();
LLDynamicArray<LLUUID> delete_items;
LLPointer<LLRefCount> cbdone = NULL;
for( i = 0; i < count; ++i )
{
@@ -7263,53 +7277,69 @@ void LLAgent::makeNewOutfit(
LLWearable* old_wearable = mWearableEntry[ index ].mWearable;
if( old_wearable )
{
std::string new_name;
LLWearable* new_wearable;
new_wearable = gWearableList.createCopy(old_wearable);
LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID);
std::string new_name = item->getName();
if (rename_clothing)
{
new_name = new_folder_name;
new_name.append(" ");
new_name.append(old_wearable->getTypeLabel());
LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
new_wearable->setName(new_name);
}
LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID);
S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
if (!found_first_item)
if (no_link || isWearableCopyable((EWearableType)index))
{
found_first_item = true;
/* set the focus to the first item */
todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
/* send the agent wearables update when done */
cbdone = new sendAgentWearablesUpdateCallback;
}
LLPointer<LLInventoryCallback> cb =
new addWearableToAgentInventoryCallback(
cbdone,
index,
new_wearable,
todo);
if (isWearableCopyable((EWearableType)index))
{
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
folder_id,
new_name,
cb);
LLWearable* new_wearable = gWearableList.createCopy(old_wearable);
if (rename_clothing)
{
new_wearable->setName(new_name);
}
S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
if (!found_first_item)
{
found_first_item = true;
/* set the focus to the first item */
todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
/* send the agent wearables update when done */
cbdone = new sendAgentWearablesUpdateCallback;
}
LLPointer<LLInventoryCallback> cb =
new addWearableToAgentInventoryCallback(
cbdone,
index,
new_wearable,
todo);
if (isWearableCopyable((EWearableType)index))
{
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getLinkedUUID(),
folder_id,
new_name,
cb);
}
else
{
move_inventory_item(
gAgent.getID(),
gAgent.getSessionID(),
item->getLinkedUUID(),
folder_id,
new_name,
cb);
}
}
else
{
move_inventory_item(
link_inventory_item(
gAgent.getID(),
gAgent.getSessionID(),
item->getUUID(),
item->getLinkedUUID(),
folder_id,
new_name,
cb);
item->getName(), // Apparently, links cannot have arbitrary names...
LLAssetType::AT_LINK,
LLPointer<LLInventoryCallback>(NULL));
}
}
}
@@ -7322,39 +7352,55 @@ void LLAgent::makeNewOutfit(
if( attachments_to_include.count() )
{
BOOL msg_started = FALSE;
LLMessageSystem* msg = gMessageSystem;
for( S32 i = 0; i < attachments_to_include.count(); i++ )
{
S32 attachment_pt = attachments_to_include[i];
LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL );
if(!attachment) continue;
LLViewerObject* attached_object = attachment->getObject();
if(!attached_object) continue;
const LLUUID& item_id = attachment->getItemID();
if(item_id.isNull()) continue;
LLInventoryItem* item = gInventory.getItem(item_id);
if(!item) continue;
if(!msg_started)
{
msg_started = TRUE;
msg->newMessage("CreateNewOutfitAttachments");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", getID());
msg->addUUID("SessionID", getSessionID());
msg->nextBlock("HeaderData");
msg->addUUID("NewFolderID", folder_id);
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) continue;
const LLUUID& item_id = attached_object->getAttachmentItemID();
if (item_id.isNull()) continue;
LLInventoryItem* item = gInventory.getItem(item_id);
if (!item) continue;
if (no_link || item->getPermissions().allowCopyBy(gAgent.getID()))
{
const LLUUID& old_folder_id = item->getParentUUID();
move_inventory_item(
gAgent.getID(),
gAgent.getSessionID(),
item->getLinkedUUID(),
folder_id,
item->getName(),
LLPointer<LLInventoryCallback>(NULL));
if (item->getPermissions().allowCopyBy(gAgent.getID()))
{
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getLinkedUUID(),
old_folder_id,
item->getName(),
LLPointer<LLInventoryCallback>(NULL));
}
}
else
{
link_inventory_item(
gAgent.getID(),
item->getLinkedUUID(),
folder_id,
item->getName(),
LLAssetType::AT_LINK,
LLPointer<LLInventoryCallback>(NULL));
}
}
msg->nextBlock("ObjectData");
msg->addUUID("OldItemID", item_id);
msg->addUUID("OldFolderID", item->getParentUUID());
}
if( msg_started )
{
sendReliableMessage();
}
}
}
@@ -8006,11 +8052,16 @@ void LLAgent::userRemoveAllAttachments( void* userdata )
{
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
LLViewerObject* objectp = attachment->getObject();
if (objectp)
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
LLViewerObject *attached_object = (*attachment_iter);
if (attached_object)
{
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
}
}
}
gMessageSystem->sendReliable( gAgent.getRegionHost() );

View File

@@ -59,9 +59,12 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento
<< ((S32) objectp->getType())
<< " (shouldn't happen)" << llendl;
}
else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category
else if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
(objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category
{
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(),
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(
objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
panelp,
objectp->getUUID());
@@ -82,6 +85,7 @@ void LLBuildNewViewsScheduler::buildNewViews(LLInventoryPanel* panelp, LLInvento
LLInventoryItem* item = (LLInventoryItem*)objectp;
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(
item->getType(),
item->getActualType(),
item->getInventoryType(),
panelp,
item->getUUID(),

View File

@@ -329,6 +329,8 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
GP_OBJECT_SET_SALE);
BOOL is_link = i->getIsLinkType();
// You need permission to modify the object to modify an inventory
// item in it.
LLViewerObject* object = NULL;
@@ -509,7 +511,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
/////////////
// Check for ability to change values.
if (is_obj_modify && can_agent_manipulate)
if (!is_link && is_obj_modify && can_agent_manipulate)
{
childSetEnabled("CheckShareWithGroup",TRUE);
childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER));

View File

@@ -4672,6 +4672,15 @@ LLInventoryFilter::~LLInventoryFilter()
BOOL LLInventoryFilter::check(LLFolderViewItem* item)
{
LLFolderViewEventListener* listener = item->getListener();
const LLUUID& item_id = listener->getUUID();
const LLInventoryObject *obj = gInventory.getObject(item_id);
if (isActive() && obj && obj->getIsLinkType())
{
// When filtering is active, omit links.
return FALSE;
}
time_t earliest;
earliest = time_corrected() - mFilterOps.mHoursAgo * 3600;
@@ -4683,8 +4692,7 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item)
{
earliest = 0;
}
LLFolderViewEventListener* listener = item->getListener();
const LLUUID& item_id = listener->getUUID();
//When searching for all labels, we need to explode the filter string
//Into an array, and then compare each string to the label seperately

View File

@@ -100,6 +100,7 @@ public:
virtual void cutToClipboard() = 0;
virtual BOOL isClipboardPasteable() const = 0;
virtual void pasteFromClipboard() = 0;
virtual void pasteLinkFromClipboard() = 0;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;
virtual BOOL isUpToDate() const = 0;
virtual BOOL hasChildren() const = 0;
@@ -382,13 +383,6 @@ protected:
BOOL mIsLoading;
LLTimer mTimeSinceRequestStart;
// This function clears the currently selected item, and records
// the specified selected item appropriately for display and use
// in the UI. If open is TRUE, then folders are opened up along
// the way to the selection.
void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem,
BOOL take_keyboard_focus = TRUE);
// helper function to change the selection from the root.
void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected);
@@ -401,6 +395,13 @@ protected:
virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; }
public:
// This function clears the currently selected item, and records
// the specified selected item appropriately for display and use
// in the UI. If open is TRUE, then folders are opened up along
// the way to the selection.
void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem,
BOOL take_keyboard_focus = TRUE);
static void initClass();
static void cleanupClass();

View File

@@ -65,6 +65,9 @@ LLGestureManager gGestureManager;
// Longest time, in seconds, to wait for all animations to stop playing
const F32 MAX_WAIT_ANIM_SECS = 30.f;
// If this gesture is a link, get the base gesture that this link points to,
// otherwise just return this id.
static const LLUUID& get_linked_uuid(const LLUUID& item_id);
// Lightweight constructor.
// init() does the heavy lifting.
@@ -212,15 +215,17 @@ void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id,
BOOL inform_server,
BOOL deactivate_similar)
{
const LLUUID& base_item_id = get_linked_uuid(item_id);
if( !gAssetStorage )
{
llwarns << "LLGestureManager::activateGestureWithAsset without valid gAssetStorage" << llendl;
return;
}
// If gesture is already active, nothing to do.
if (isGestureActive(item_id))
if (isGestureActive(base_item_id))
{
llwarns << "Tried to loadGesture twice " << item_id << llendl;
llwarns << "Tried to loadGesture twice " << base_item_id << llendl;
return;
}
@@ -232,13 +237,13 @@ void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id,
// For now, put NULL into the item map. We'll build a gesture
// class object when the asset data arrives.
mActive[item_id] = NULL;
mActive[base_item_id] = NULL;
// Copy the UUID
if (asset_id.notNull())
{
LLLoadInfo* info = new LLLoadInfo;
info->mItemID = item_id;
info->mItemID = base_item_id;
info->mInformServer = inform_server;
info->mDeactivateSimilar = deactivate_similar;
@@ -258,10 +263,11 @@ void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id,
void LLGestureManager::deactivateGesture(const LLUUID& item_id)
{
item_map_t::iterator it = mActive.find(item_id);
const LLUUID& base_item_id = get_linked_uuid(item_id);
item_map_t::iterator it = mActive.find(base_item_id);
if (it == mActive.end())
{
llwarns << "deactivateGesture for inactive gesture " << item_id << llendl;
llwarns << "deactivateGesture for inactive gesture " << base_item_id << llendl;
return;
}
@@ -278,7 +284,7 @@ void LLGestureManager::deactivateGesture(const LLUUID& item_id)
}
mActive.erase(it);
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id);
// Inform the database of this change
LLMessageSystem* msg = gMessageSystem;
@@ -289,7 +295,7 @@ void LLGestureManager::deactivateGesture(const LLUUID& item_id)
msg->addU32("Flags", 0x0);
msg->nextBlock("Data");
msg->addUUID("ItemID", item_id);
msg->addUUID("ItemID", base_item_id);
msg->addU32("GestureFlags", 0x0);
gAgent.sendReliableMessage();
@@ -300,6 +306,7 @@ void LLGestureManager::deactivateGesture(const LLUUID& item_id)
void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id)
{
const LLUUID& base_in_item_id = get_linked_uuid(in_item_id);
std::vector<LLUUID> gest_item_ids;
// Deactivate all gestures that match
@@ -311,7 +318,7 @@ void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUI
// Don't deactivate the gesture we are looking for duplicates of
// (for replaceGesture)
if (!gest || item_id == in_item_id)
if (!gest || item_id == base_in_item_id)
{
// legal, can have null pointers in list
++it;
@@ -386,14 +393,16 @@ void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUI
BOOL LLGestureManager::isGestureActive(const LLUUID& item_id)
{
item_map_t::iterator it = mActive.find(item_id);
const LLUUID& base_item_id = get_linked_uuid(item_id);
item_map_t::iterator it = mActive.find(base_item_id);
return (it != mActive.end());
}
BOOL LLGestureManager::isGesturePlaying(const LLUUID& item_id)
{
item_map_t::iterator it = mActive.find(item_id);
const LLUUID& base_item_id = get_linked_uuid(item_id);
item_map_t::iterator it = mActive.find(base_item_id);
if (it == mActive.end()) return FALSE;
LLMultiGesture* gesture = (*it).second;
@@ -404,19 +413,20 @@ BOOL LLGestureManager::isGesturePlaying(const LLUUID& item_id)
void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id)
{
item_map_t::iterator it = mActive.find(item_id);
const LLUUID& base_item_id = get_linked_uuid(item_id);
item_map_t::iterator it = mActive.find(base_item_id);
if (it == mActive.end())
{
llwarns << "replaceGesture for inactive gesture " << item_id << llendl;
llwarns << "replaceGesture for inactive gesture " << base_item_id << llendl;
return;
}
LLMultiGesture* old_gesture = (*it).second;
stopGesture(old_gesture);
mActive.erase(item_id);
mActive.erase(base_item_id);
mActive[item_id] = new_gesture;
mActive[base_item_id] = new_gesture;
delete old_gesture;
old_gesture = NULL;
@@ -427,7 +437,7 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new
mDeactivateSimilarNames.clear();
LLLoadInfo* info = new LLLoadInfo;
info->mItemID = item_id;
info->mItemID = base_item_id;
info->mInformServer = TRUE;
info->mDeactivateSimilar = FALSE;
@@ -444,7 +454,8 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new
void LLGestureManager::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id)
{
item_map_t::iterator it = gGestureManager.mActive.find(item_id);
const LLUUID& base_item_id = get_linked_uuid(item_id);
item_map_t::iterator it = gGestureManager.mActive.find(base_item_id);
if (it == mActive.end())
{
llwarns << "replaceGesture for inactive gesture " << item_id << llendl;
@@ -453,7 +464,7 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, const LLUUID& new_a
// mActive owns this gesture pointer, so clean up memory.
LLMultiGesture* gesture = (*it).second;
gGestureManager.replaceGesture(item_id, gesture, new_asset_id);
gGestureManager.replaceGesture(base_item_id, gesture, new_asset_id);
}
void LLGestureManager::playGesture(LLMultiGesture* gesture)
@@ -477,7 +488,8 @@ void LLGestureManager::playGesture(LLMultiGesture* gesture)
// Convenience function that looks up the item_id for you.
void LLGestureManager::playGesture(const LLUUID& item_id)
{
item_map_t::iterator it = mActive.find(item_id);
const LLUUID& base_item_id = get_linked_uuid(item_id);
item_map_t::iterator it = mActive.find(base_item_id);
if (it == mActive.end()) return;
LLMultiGesture* gesture = (*it).second;
@@ -1144,3 +1156,14 @@ void LLGestureManager::getItemIDs(std::vector<LLUUID>* ids)
ids->push_back(it->first);
}
}
// static
const LLUUID& get_linked_uuid(const LLUUID &item_id)
{
LLViewerInventoryItem* item = gInventory.getItem(item_id);
if (item && item->getIsLinkType())
{
return item->getLinkedUUID();
}
return item_id;
}

View File

@@ -784,8 +784,6 @@ class LLBeginIMSession : public inventory_panel_listener_t
}
};
void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment);
class LLAttachObject : public inventory_panel_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)

File diff suppressed because it is too large Load Diff

View File

@@ -30,7 +30,13 @@
* $/LicenseInfo$
*/
#ifndef LL_LLINVENTORYBRIDGE_H
#define LL_LLINVENTORYBRIDGE_H
#include "llfloaterproperties.h"
#include "llfolderview.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llwearable.h"
#include "llviewercontrol.h"
#include "llcallingcard.h"
@@ -70,6 +76,9 @@ enum EInventoryIcon
ANIMATION_ICON_NAME,
GESTURE_ICON_NAME,
LINKITEM_ICON_NAME,
LINKFOLDER_ICON_NAME,
ICON_NAME_COUNT
};
@@ -187,10 +196,11 @@ public:
// This method is a convenience function which creates the correct
// type of bridge based on some basic information
static LLInvFVBridge* createBridge(LLAssetType::EType asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
const LLUUID& uuid,
U32 flags = 0x00);
LLAssetType::EType actual_asset_type,
LLInventoryType::EType inv_type,
LLInventoryPanel* inventory,
const LLUUID& uuid,
U32 flags = 0x00);
virtual ~LLInvFVBridge() {}
virtual const LLUUID& getUUID() const { return mUUID; }
@@ -223,7 +233,9 @@ public:
virtual BOOL copyToClipboard() const { return FALSE; }
virtual void cutToClipboard() {}
virtual BOOL isClipboardPasteable() const;
virtual BOOL isClipboardPasteableAsLink() const;
virtual void pasteFromClipboard() {}
virtual void pasteLinkFromClipboard() {}
void getClipboardEntries(bool show_asset_id, std::vector<std::string> &items,
std::vector<std::string> &disabled_items, U32 flags);
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
@@ -242,6 +254,8 @@ protected:
LLInventoryObject* getInventoryObject() const;
BOOL isInTrash() const;
BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash?
BOOL isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory?
// return true if the item is in agent inventory. if false, it
// must be lost or in the inventory library.
BOOL isAgentInventory() const;
@@ -275,6 +289,7 @@ public:
virtual void restoreItem();
virtual void restoreToWorld();
virtual void gotoItem(LLFolderView *folder);
virtual LLUIImagePtr getIcon() const;
virtual const std::string& getDisplayName() const;
virtual std::string getLabelSuffix() const;
@@ -320,7 +335,9 @@ public:
virtual BOOL renameItem(const std::string& new_name);
virtual BOOL removeItem();
virtual BOOL isClipboardPasteable() const;
virtual BOOL isClipboardPasteableAsLink() const;
virtual void pasteFromClipboard();
virtual void pasteLinkFromClipboard();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual BOOL hasChildren() const;
virtual BOOL dragOrDrop(MASK mask, BOOL drop,
@@ -647,3 +664,47 @@ protected:
LLInventoryType::EType mInvType;
EWearableType mWearableType;
};
class LLLinkItemBridge : public LLItemBridge
{
friend class LLInvFVBridge;
public:
virtual const std::string& getPrefix() { return sPrefix; }
virtual LLUIImagePtr getIcon() const;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
protected:
LLLinkItemBridge(LLInventoryPanel* inventory, const LLUUID& uuid) :
LLItemBridge(inventory, uuid) {}
protected:
static std::string sPrefix;
};
class LLLinkFolderBridge : public LLItemBridge
{
friend class LLInvFVBridge;
public:
virtual const std::string& getPrefix() { return sPrefix; }
virtual LLUIImagePtr getIcon() const;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);
virtual void gotoItem(LLFolderView *folder);
protected:
LLLinkFolderBridge(LLInventoryPanel* inventory, const LLUUID& uuid) :
LLItemBridge(inventory, uuid) {}
const LLUUID &getFolderID() const;
protected:
static std::string sPrefix;
};
void rez_attachment(LLViewerInventoryItem* item,
LLViewerJointAttachment* attachment,
bool replace = false);
#endif // LL_LLINVENTORYBRIDGE_H

View File

@@ -83,6 +83,10 @@ S16 LLInventoryModel::sBulkFetchCount = 0;
// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue
static std::deque<LLUUID> sFetchQueue;
// Increment this if the inventory contents change in a non-backwards-compatible way.
// For viewers with link items support, former caches are incorrect.
const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
@@ -568,6 +572,54 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
}
}
void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)
{
const LLInventoryObject *obj = getObject(object_id);
if (!obj || obj->getIsLinkType())
return;
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
LLLinkedItemIDMatches is_linked_item_match(object_id);
collectDescendentsIf(gAgent.getInventoryRootID(),
cat_array,
item_array,
LLInventoryModel::INCLUDE_TRASH,
is_linked_item_match);
if (cat_array.empty() && item_array.empty())
{
return;
}
for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin();
cat_iter != cat_array.end();
cat_iter++)
{
LLViewerInventoryCategory *linked_cat = (*cat_iter);
addChangedMask(mask, linked_cat->getUUID());
};
for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
iter != item_array.end();
iter++)
{
LLViewerInventoryItem *linked_item = (*iter);
addChangedMask(mask, linked_item->getUUID());
};
}
const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const
{
const LLInventoryItem *item = gInventory.getItem(object_id);
if (!item)
{
return object_id;
}
// Find the base item in case this a link (if it's not a link,
// this will just be inv_item_id)
return item->getLinkedUUID();
}
// Generates a string containing the path to the item specified by
// item_id.
void LLInventoryModel::appendPath(const LLUUID& id, std::string& path)
@@ -1099,6 +1151,12 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)
{
mChangedItemIDs.insert(referent);
}
// Update all linked items. Starting with just LABEL because I'm
// not sure what else might need to be accounted for this.
if (mModifyMask & LLInventoryObserver::LABEL)
{
addChangedMaskForLinks(referent, LLInventoryObserver::LABEL);
}
}
// This method to prepares a set of mock inventory which provides
@@ -2062,6 +2120,7 @@ bool LLInventoryModel::loadSkeleton(
{
cat_array_t categories;
item_array_t items;
cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded.
std::string owner_id_str;
owner_id.toString(owner_id_str);
std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str));
@@ -2088,7 +2147,8 @@ bool LLInventoryModel::loadSkeleton(
llinfos << "Unable to gunzip " << gzip_filename << llendl;
}
}
if (loadFromFile(inventory_filename, categories, items))
bool is_cache_obsolete = false;
if (loadFromFile(inventory_filename, categories, items, is_cache_obsolete))
{
// We were able to find a cache of files. So, use what we
// found to generate a set of categories we should add. We
@@ -2146,6 +2206,7 @@ bool LLInventoryModel::loadSkeleton(
// Add all the items loaded which are parented to a
// category with a correctly cached parent
count = items.count();
S32 bad_link_count = 0;
cat_map_t::iterator unparented = mCategoryMap.end();
for (int i = 0; i < count; ++i)
{
@@ -2156,12 +2217,29 @@ bool LLInventoryModel::loadSkeleton(
LLViewerInventoryCategory* cat = cit->second;
if (cat->getVersion() != NO_VERSION)
{
// This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache.
if (items[i]->getIsBrokenLink())
{
bad_link_count++;
lldebugs << "Attempted to add cached link item without baseobj present ( name: "
<< items[i]->getName() << " itemID: " << items[i]->getUUID()
<< " assetID: " << items[i]->getAssetUUID()
<< " ). Ignoring and invalidating " << cat->getName() << " . " << llendl;
invalid_categories.insert(cit->second);
continue;
}
addItem(items[i]);
cached_item_count += 1;
++child_counts[cat->getUUID()];
}
}
}
if (bad_link_count > 0)
{
llinfos << "Attempted to add " << bad_link_count
<< " cached link items without baseobj present. "
<< "The corresponding categories were invalidated." << llendl;
}
}
else
{
@@ -2175,6 +2253,17 @@ bool LLInventoryModel::loadSkeleton(
}
}
// Invalidate all categories that failed fetching descendents for whatever
// reason (e.g. one of the descendents was a broken link).
for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin();
invalid_cat_it != invalid_categories.end();
invalid_cat_it++)
{
LLViewerInventoryCategory* cat = (*invalid_cat_it).get();
cat->setVersion(NO_VERSION);
llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl;
}
// At this point, we need to set the known descendents for each
// category which successfully cached so that we do not
// needlessly fetch descendents for categories which we have.
@@ -2202,6 +2291,12 @@ bool LLInventoryModel::loadSkeleton(
// clean up the gunzipped file.
LLFile::remove(inventory_filename);
}
if (is_cache_obsolete)
{
// If out of date, remove the gzipped file too.
llwarns << "Inv cache out of date, removing" << llendl;
LLFile::remove(gzip_filename);
}
categories.clear(); // will unref and delete entries
}
@@ -2273,6 +2368,7 @@ bool LLInventoryModel::loadSkeleton(
cat_array_t categories;
item_array_t items;
std::string owner_id_str;
cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded.
owner_id.toString(owner_id_str);
std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str));
std::string inventory_filename;
@@ -2298,7 +2394,8 @@ bool LLInventoryModel::loadSkeleton(
llinfos << "Unable to gunzip " << gzip_filename << llendl;
}
}
if(loadFromFile(inventory_filename, categories, items))
bool is_cache_obsolete = false;
if (loadFromFile(inventory_filename, categories, items, is_cache_obsolete))
{
// We were able to find a cache of files. So, use what we
// found to generate a set of categories we should add. We
@@ -2356,6 +2453,7 @@ bool LLInventoryModel::loadSkeleton(
// Add all the items loaded which are parented to a
// category with a correctly cached parent
count = items.count();
S32 bad_link_count = 0;
cat_map_t::iterator unparented = mCategoryMap.end();
for(int i = 0; i < count; ++i)
{
@@ -2366,12 +2464,29 @@ bool LLInventoryModel::loadSkeleton(
LLViewerInventoryCategory* cat = cit->second;
if(cat->getVersion() != NO_VERSION)
{
// This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache.
if (items[i]->getIsBrokenLink())
{
bad_link_count++;
lldebugs << "Attempted to add cached link item without baseobj present ( name: "
<< items[i]->getName() << " itemID: " << items[i]->getUUID()
<< " assetID: " << items[i]->getAssetUUID()
<< " ). Ignoring and invalidating " << cat->getName() << " . " << llendl;
invalid_categories.insert(cit->second);
continue;
}
addItem(items[i]);
cached_item_count += 1;
++child_counts[cat->getUUID()];
}
}
}
if (bad_link_count > 0)
{
llinfos << "Attempted to add " << bad_link_count
<< " cached link items without baseobj present. "
<< "The corresponding categories were invalidated." << llendl;
}
}
else
{
@@ -2384,6 +2499,16 @@ bool LLInventoryModel::loadSkeleton(
addCategory(*it);
}
}
// Invalidate all categories that failed fetching descendents for whatever
// reason (e.g. one of the descendents was a broken link).
for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin();
invalid_cat_it != invalid_categories.end();
invalid_cat_it++)
{
LLViewerInventoryCategory* cat = (*invalid_cat_it).get();
cat->setVersion(NO_VERSION);
llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl;
}
// At this point, we need to set the known descendents for each
// category which successfully cached so that we do not
@@ -2412,6 +2537,12 @@ bool LLInventoryModel::loadSkeleton(
// clean up the gunzipped file.
LLFile::remove(inventory_filename);
}
if (is_cache_obsolete)
{
// If out of date, remove the gzipped file too.
llwarns << "Inv cache out of date, removing" << llendl;
LLFile::remove(gzip_filename);
}
categories.clear(); // will unref and delete entries
}
@@ -2809,7 +2940,8 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const
// static
bool LLInventoryModel::loadFromFile(const std::string& filename,
LLInventoryModel::cat_array_t& categories,
LLInventoryModel::item_array_t& items)
LLInventoryModel::item_array_t& items,
bool &is_cache_obsolete)
{
if(filename.empty())
{
@@ -2826,11 +2958,32 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
// *NOTE: This buffer size is hard coded into scanf() below.
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
char keyword[MAX_STRING]; /*Flawfinder: ignore*/
char value[MAX_STRING]; /*Flawfinder: ignore*/
is_cache_obsolete = true; // Obsolete until proven current
while(!feof(file) && fgets(buffer, MAX_STRING, file))
{
sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */
if(0 == strcmp("inv_category", keyword))
sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */
if (0 == strcmp("inv_cache_version", keyword))
{
S32 version;
int succ = sscanf(value,"%d",&version);
if ((1 == succ) && (version == sCurrentInvCacheVersion))
{
// Cache is up to date
is_cache_obsolete = false;
continue;
}
else
{
// Cache is out of date
break;
}
}
else if(0 == strcmp("inv_category", keyword))
{
if (is_cache_obsolete)
break;
LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
if(inv_cat->importFileLocal(file))
{
@@ -2875,6 +3028,10 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
}
}
fclose(file);
if (is_cache_obsolete)
return false;
return true;
}
@@ -2896,6 +3053,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
return false;
}
fprintf(file, "\tinv_cache_version\t%d\n", sCurrentInvCacheVersion);
S32 count = categories.count();
S32 i;
for(i = 0; i < count; ++i)
@@ -3455,6 +3613,12 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)
for(i = 0; i < count; ++i)
{
titem->unpackMessage(msg, _PREHASH_ItemData, i);
// If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added.
if (gInventory.getItem(titem->getUUID()))
{
lldebugs << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl;
continue;
}
gInventory.updateItem(titem);
}
@@ -4261,6 +4425,16 @@ bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* it
}
///----------------------------------------------------------------------------
/// LLLinkedItemIDMatches
///----------------------------------------------------------------------------
bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item &&
(item->getIsLinkType()) &&
(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
}
///----------------------------------------------------------------------------
/// Local function definitions
///----------------------------------------------------------------------------

View File

@@ -185,6 +185,10 @@ public:
BOOL include_trash,
LLInventoryCollectFunctor& add);
// Get the inventoryID that this item points to, else just return item_id
const LLUUID& getLinkedItemID(const LLUUID& object_id) const;
// This method will return false if this inventory model is in an usabel state.
// The inventory model usage is sensitive to the initial construction of the
// model.
@@ -415,7 +419,9 @@ public:
// </edit>
static bool loadFromFile(const std::string& filename,
cat_array_t& categories,
item_array_t& items);
item_array_t& items,
bool& is_cache_obsolete);
static bool saveToFile(const std::string& filename,
const cat_array_t& categories,
const item_array_t& items);
@@ -439,6 +445,8 @@ protected:
static void processFetchInventoryReply(LLMessageSystem* msg, void**);
bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting);
// Updates all linked items pointing to this id.
void addChangedMaskForLinks(const LLUUID& object_id, U32 mask);
protected:
cat_array_t* getUnlockedCatArray(const LLUUID& id);
@@ -488,6 +496,9 @@ protected:
// This flag is used to handle an invalid inventory state.
bool mIsAgentInvUsable;
private:
const static S32 sCurrentInvCacheVersion; // expected inventory cache version
public:
// *NOTE: DEBUG functionality
void dumpInventory();
@@ -540,6 +551,23 @@ protected:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLLinkedItemIDMatches
//
// This functor finds inventory items linked to the specific inventory id.
// Assumes the inventory id is itself not a linked item.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLLinkedItemIDMatches : public LLInventoryCollectFunctor
{
public:
LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {}
virtual ~LLLinkedItemIDMatches() {}
bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
protected:
LLUUID mBaseItemID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsType
//

View File

@@ -1937,9 +1937,11 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id)
<< " for object " << objectp->getName()
<< " (shouldn't happen)" << llendl;
}
else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category
else if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
(objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category
{
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
this,
objectp->getUUID());
@@ -1960,6 +1962,7 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id)
LLInventoryItem* item = (LLInventoryItem*)objectp;
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(
item->getType(),
item->getActualType(),
item->getInventoryType(),
this,
item->getUUID(),
@@ -2043,6 +2046,7 @@ void LLInventoryPanel::buildNewViews(const LLInventoryObject* objectp)
else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category
{
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
this,
objectp->getUUID());
@@ -2063,9 +2067,10 @@ void LLInventoryPanel::buildNewViews(const LLInventoryObject* objectp)
LLInventoryItem* item = (LLInventoryItem*)objectp;
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(
item->getType(),
item->getInventoryType(),
this,
item->getUUID(),
item->getActualType(),
item->getInventoryType(),
this,
item->getUUID(),
item->getFlags());
if (new_listener)
{

View File

@@ -419,8 +419,6 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
const BOOL TAKE_FOCUS_YES = TRUE;
const BOOL TAKE_FOCUS_NO = FALSE;
void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment);
#endif // LL_LLINVENTORYVIEW_H

View File

@@ -176,7 +176,8 @@ void LLLocalInventory::loadInvCache(std::string filename)
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
if(LLInventoryModel::loadFromFile(inv_filename, cats, items))
bool is_cache_obsolete = false;
if(LLInventoryModel::loadFromFile(inv_filename, cats, items, is_cache_obsolete))
{
// create a container category for everything
LLViewerInventoryCategory* container = new LLViewerInventoryCategory(gAgent.getID());

View File

@@ -142,6 +142,7 @@ public:
virtual void cutToClipboard();
virtual BOOL isClipboardPasteable() const;
virtual void pasteFromClipboard();
virtual void pasteLinkFromClipboard();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);
virtual BOOL isUpToDate() const { return TRUE; }
@@ -550,6 +551,10 @@ void LLTaskInvFVBridge::pasteFromClipboard()
{
}
void LLTaskInvFVBridge::pasteLinkFromClipboard()
{
}
BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
{
//llinfos << "LLTaskInvFVBridge::startDrag()" << llendl;

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@
#include "llgesturemgr.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llmutelist.h"
@@ -477,6 +478,15 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT]
&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
},
// Source: DAD_LINK
// TODO: gesture on self could play it? edit it?
{
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
&LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
},
};
LLToolDragAndDrop::LLToolDragAndDrop()
@@ -1986,6 +1996,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
//if(!vitem->isComplete()) return ACCEPT_NO;
if(!vitem->isComplete() && !(gInventory.isObjectDescendentOf(vitem->getUUID(), gLocalInventoryRoot))) return ACCEPT_NO;
// </edit>
if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links
// deny attempts to drop from an object onto itself. This is to
// help make sure that drops that are from an object to an object

View File

@@ -44,6 +44,7 @@
#include "llimview.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryview.h"
#include "llviewerregion.h"
@@ -672,9 +673,10 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item)
}
}
RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp)
RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp, bool replace)
{
mAttach = attachmentp;
mReplace = replace;
}
RezAttachmentCallback::~RezAttachmentCallback()
{
@@ -688,7 +690,7 @@ void RezAttachmentCallback::fire(const LLUUID& inv_item)
LLViewerInventoryItem *item = gInventory.getItem(inv_item);
if (item)
{
rez_attachment(item, mAttach);
rez_attachment(item, mAttach, mReplace);
}
}
@@ -772,6 +774,72 @@ void copy_inventory_item(
gAgent.sendReliableMessage();
}
void link_inventory_item(
const LLUUID& agent_id,
const LLUUID& item_id,
const LLUUID& parent_id,
const std::string& new_name,
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb)
{
const LLInventoryObject *baseobj = gInventory.getObject(item_id);
if (!baseobj)
{
llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl;
return;
}
if (baseobj && baseobj->getIsLinkType())
{
llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl;
return;
}
if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType()))
{
// Fail if item can be found but is of a type that can't be linked.
// Arguably should fail if the item can't be found too, but that could
// be a larger behavioral change.
llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl;
return;
}
LLUUID transaction_id;
std::string desc = "Broken link"; // This should only show if the object can't find its baseobj.
LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
if (dynamic_cast<const LLInventoryCategory *>(baseobj))
{
inv_type = LLInventoryType::IT_CATEGORY;
}
else
{
const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj);
if (baseitem)
{
inv_type = baseitem->getInventoryType();
}
}
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_LinkInventoryItem);
msg->nextBlock(_PREHASH_AgentData);
{
msg->addUUIDFast(_PREHASH_AgentID, agent_id);
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
}
msg->nextBlock(_PREHASH_InventoryBlock);
{
msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
msg->addUUIDFast(_PREHASH_FolderID, parent_id);
msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
msg->addUUIDFast(_PREHASH_OldItemID, item_id);
msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
msg->addStringFast(_PREHASH_Name, new_name);
msg->addStringFast(_PREHASH_Description, desc);
}
gAgent.sendReliableMessage();
}
void move_inventory_item(
const LLUUID& agent_id,
const LLUUID& session_id,
@@ -846,3 +914,139 @@ void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecar
}
}
}
LLAssetType::EType LLViewerInventoryItem::getType() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getType();
}
if (const LLViewerInventoryCategory *linked_category = getLinkedCategory())
{
return linked_category->getType();
}
return LLInventoryItem::getType();
}
const LLUUID& LLViewerInventoryItem::getAssetUUID() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getAssetUUID();
}
return LLInventoryItem::getAssetUUID();
}
const std::string& LLViewerInventoryItem::getName() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getName();
}
if (const LLViewerInventoryCategory *linked_category = getLinkedCategory())
{
return linked_category->getName();
}
return LLInventoryItem::getName();
}
const LLPermissions& LLViewerInventoryItem::getPermissions() const
{
// Use the actual permissions of the symlink, not its parent.
return LLInventoryItem::getPermissions();
}
const LLUUID& LLViewerInventoryItem::getCreatorUUID() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getCreatorUUID();
}
return LLInventoryItem::getCreatorUUID();
}
const std::string& LLViewerInventoryItem::getDescription() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getDescription();
}
return LLInventoryItem::getDescription();
}
const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getSaleInfo();
}
return LLInventoryItem::getSaleInfo();
}
LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getInventoryType();
}
// Categories don't have types. If this item is an AT_FOLDER_LINK,
// treat it as a category.
if (getLinkedCategory())
{
return LLInventoryType::IT_CATEGORY;
}
return LLInventoryItem::getInventoryType();
}
U32 LLViewerInventoryItem::getFlags() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getFlags();
}
return LLInventoryItem::getFlags();
}
// This returns true if the item that this item points to
// doesn't exist in memory (i.e. LLInventoryModel). The baseitem
// might still be in the database but just not loaded yet.
bool LLViewerInventoryItem::getIsBrokenLink() const
{
// If the item's type resolves to be a link, that means either:
// A. It wasn't able to perform indirection, i.e. the baseobj doesn't exist in memory.
// B. It's pointing to another link, which is illegal.
return LLAssetType::lookupIsLinkType(getType());
}
LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const
{
if (mType == LLAssetType::AT_LINK)
{
LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
if (linked_item && linked_item->getIsLinkType())
{
llwarns << "Warning: Accessing link to link" << llendl;
return NULL;
}
return linked_item;
}
return NULL;
}
LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const
{
if (mType == LLAssetType::AT_LINK_FOLDER)
{
LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID);
return linked_category;
}
return NULL;
}

View File

@@ -37,6 +37,8 @@
#include "llframetimer.h"
#include "llwearable.h"
class LLViewerInventoryCategory;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLViewerInventoryItem
//
@@ -53,6 +55,16 @@ protected:
~LLViewerInventoryItem( void ); // ref counted
public:
virtual LLAssetType::EType getType() const;
virtual const LLUUID& getAssetUUID() const;
virtual const std::string& getName() const;
virtual const LLPermissions& getPermissions() const;
virtual const LLUUID& getCreatorUUID() const;
virtual const std::string& getDescription() const;
virtual const LLSaleInfo& getSaleInfo() const;
virtual LLInventoryType::EType getInventoryType() const;
virtual U32 getFlags() const;
// construct a complete viewer inventory item
LLViewerInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid,
const LLPermissions& permissions,
@@ -125,6 +137,10 @@ public:
};
LLTransactionID getTransactionID() const { return mTransactionID; }
bool getIsBrokenLink() const; // true if the baseitem this points to doesn't exist in memory.
LLViewerInventoryItem *getLinkedItem() const;
LLViewerInventoryCategory *getLinkedCategory() const;
protected:
BOOL mIsComplete;
LLTransactionID mTransactionID;
@@ -208,7 +224,7 @@ class LLViewerJointAttachment;
class RezAttachmentCallback : public LLInventoryCallback
{
public:
RezAttachmentCallback(LLViewerJointAttachment *attachmentp);
RezAttachmentCallback(LLViewerJointAttachment *attachmentp, bool replace = false);
void fire(const LLUUID& inv_item);
protected:
@@ -216,6 +232,7 @@ protected:
private:
LLViewerJointAttachment* mAttach;
bool mReplace;
};
class ActivateGestureCallback : public LLInventoryCallback
@@ -272,6 +289,14 @@ void copy_inventory_item(
const std::string& new_name,
LLPointer<LLInventoryCallback> cb);
void link_inventory_item(
const LLUUID& agent_id,
const LLUUID& item_id,
const LLUUID& parent_id,
const std::string& new_name,
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb);
void move_inventory_item(
const LLUUID& agent_id,
const LLUUID& session_id,

View File

@@ -57,7 +57,6 @@ extern LLPipeline gPipeline;
// LLViewerJointAttachment()
//-----------------------------------------------------------------------------
LLViewerJointAttachment::LLViewerJointAttachment() :
mAttachedObject(NULL),
mVisibleInFirst(FALSE),
mGroup(0),
mIsHUDAttachment(FALSE),
@@ -65,6 +64,7 @@ mPieSlice(-1)
{
mValid = FALSE;
mUpdateXform = FALSE;
mAttachedObjects.clear();
}
//-----------------------------------------------------------------------------
@@ -103,12 +103,19 @@ U32 LLViewerJointAttachment::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_
return 0;
}
void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep)
void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
{
drawablep->mXform.setParent(&mXform); // LLViewerJointAttachment::lazyAttach
drawablep->makeActive();
LLVector3 current_pos = mAttachedObject->getRenderPosition();
LLQuaternion current_rot = mAttachedObject->getRenderRotation();
if (!object->mDrawable)
return;
if (object->mDrawable->isActive())
{
object->mDrawable->makeStatic(FALSE);
}
object->mDrawable->mXform.setParent(getXform()); // LLViewerJointAttachment::lazyAttach
object->mDrawable->makeActive();
LLVector3 current_pos = object->getRenderPosition();
LLQuaternion current_rot = object->getRenderRotation();
LLQuaternion attachment_pt_inv_rot = ~getWorldRotation();
current_pos -= getWorldPosition();
@@ -116,21 +123,21 @@ void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep)
current_rot = current_rot * attachment_pt_inv_rot;
drawablep->mXform.setPosition(current_pos);
drawablep->mXform.setRotation(current_rot);
gPipeline.markMoved(drawablep);
gPipeline.markTextured(drawablep); // face may need to change draw pool to/from POOL_HUD
drawablep->setState(LLDrawable::USE_BACKLIGHT);
object->mDrawable->mXform.setPosition(current_pos);
object->mDrawable->mXform.setRotation(current_rot);
gPipeline.markMoved(object->mDrawable);
gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD
object->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
if(mIsHUDAttachment)
{
for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++)
for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++)
{
drawablep->getFace(face_num)->setState(LLFace::HUD_RENDER);
object->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER);
}
}
LLViewerObject::const_child_list_t& child_list = mAttachedObject->getChildren();
LLViewerObject::const_child_list_t& child_list = object->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
{
@@ -157,54 +164,18 @@ void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep)
//-----------------------------------------------------------------------------
BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
{
if (mAttachedObject)
{
llwarns << "Attempted to attach object where an attachment already exists!" << llendl;
if (mAttachedObject == object) {
llinfos << "(same object re-attached)" << llendl;
removeObject(mAttachedObject);
// Pass through anyway to let setupDrawable()
// re-connect object to the joint correctly
}
else {
llinfos << "(objects differ, removing existing object)" << llendl;
// Rather hacky, but no-one can think of something
// better to do for this case.
gObjectList.killObject(mAttachedObject);
// Proceed with new object attachment
}
}
mAttachedObject = object;
LLUUID item_id;
object->extractAttachmentItemID();
// Find the inventory item ID of the attached object
LLNameValue* item_id_nv = object->getNVPair("AttachItemID");
if( item_id_nv )
if (isObjectAttached(object))
{
const char* s = item_id_nv->getString();
if( s )
{
item_id.set( s );
lldebugs << "getNVPair( AttachItemID ) = " << item_id << llendl;
}
llinfos << "(same object re-attached)" << llendl;
removeObject(object);
// Pass through anyway to let setupDrawable()
// re-connect object to the joint correctly
}
mItemID = item_id;
LLDrawable* drawablep = object->mDrawable;
if (drawablep)
{
//if object is active, make it static
if(drawablep->isActive())
{
drawablep->makeStatic(FALSE) ;
}
setupDrawable(drawablep);
}
mAttachedObjects.push_back(object);
setupDrawable(object);
if (mIsHUDAttachment)
{
@@ -234,9 +205,28 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)
//-----------------------------------------------------------------------------
void LLViewerJointAttachment::removeObject(LLViewerObject *object)
{
attachedobjs_vec_t::iterator iter;
for (iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
LLViewerObject *attached_object = (*iter);
if (attached_object == object)
{
break;
}
}
if (iter == mAttachedObjects.end())
{
llwarns << "Could not find object to detach" << llendl;
return;
}
// force object visibile
setAttachmentVisibility(TRUE);
mAttachedObjects.erase(iter);
if (object->mDrawable.notNull())
{
//if object is active, make it static
@@ -300,9 +290,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
}
}
mAttachedObject = NULL;
mUpdateXform = FALSE;
mItemID.setNull();
if (mAttachedObjects.size() == 0)
{
mUpdateXform = FALSE;
}
object->setAttachmentItemID(LLUUID::null);
}
//-----------------------------------------------------------------------------
@@ -310,20 +302,26 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
//-----------------------------------------------------------------------------
void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible)
{
if (!mAttachedObject || mAttachedObject->mDrawable.isNull() ||
!(mAttachedObject->mDrawable->getSpatialBridge()))
return;
if (visible)
for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
// Hack to make attachments not visible by disabling their type mask!
// This will break if you can ever attach non-volumes! - djs 02/14/03
mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType =
mAttachedObject->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME;
}
else
{
mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType = 0;
LLViewerObject *attached_obj = (*iter);
if (!attached_obj || attached_obj->mDrawable.isNull() ||
!(attached_obj->mDrawable->getSpatialBridge()))
continue;
if (visible)
{
// Hack to make attachments not visible by disabling their type mask!
// This will break if you can ever attach non-volumes! - djs 02/14/03
attached_obj->mDrawable->getSpatialBridge()->mDrawableType =
attached_obj->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME;
}
else
{
attached_obj->mDrawable->getSpatialBridge()->mDrawableType = 0;
}
}
}
@@ -341,14 +339,19 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position)
//-----------------------------------------------------------------------------
void LLViewerJointAttachment::clampObjectPosition()
{
if (mAttachedObject)
for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
// *NOTE: object can drift when hitting maximum radius
LLVector3 attachmentPos = mAttachedObject->getPosition();
F32 dist = attachmentPos.normVec();
dist = llmin(dist, MAX_ATTACHMENT_DIST);
attachmentPos *= dist;
mAttachedObject->setPosition(attachmentPos);
if (LLViewerObject *attached_object = (*iter))
{
// *NOTE: object can drift when hitting maximum radius
LLVector3 attachmentPos = attached_object->getPosition();
F32 dist = attachmentPos.normVec();
dist = llmin(dist, MAX_ATTACHMENT_DIST);
attachmentPos *= dist;
attached_object->setPosition(attachmentPos);
}
}
}
@@ -357,14 +360,23 @@ void LLViewerJointAttachment::clampObjectPosition()
//-----------------------------------------------------------------------------
void LLViewerJointAttachment::calcLOD()
{
F32 maxarea = mAttachedObject->getMaxScale() * mAttachedObject->getMidScale();
LLViewerObject::const_child_list_t& child_list = mAttachedObject->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
F32 maxarea = 0;
for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
LLViewerObject* childp = *iter;
F32 area = childp->getMaxScale() * childp->getMidScale();
maxarea = llmax(maxarea, area);
if (LLViewerObject *attached_object = (*iter))
{
maxarea = llmax(maxarea,attached_object->getMaxScale() * attached_object->getMidScale());
LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); ++iter)
{
LLViewerObject* childp = *iter;
F32 area = childp->getMaxScale() * childp->getMidScale();
maxarea = llmax(maxarea, area);
}
}
}
maxarea = llclamp(maxarea, .01f*.01f, 1.f);
F32 avatar_area = (4.f * 4.f); // pixels for an avatar sized attachment
@@ -386,3 +398,47 @@ BOOL LLViewerJointAttachment::updateLOD(F32 pixel_area, BOOL activate)
return res;
}
BOOL LLViewerJointAttachment::isObjectAttached(const LLViewerObject *viewer_object) const
{
for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
const LLViewerObject* attached_object = (*iter);
if (attached_object == viewer_object)
{
return TRUE;
}
}
return FALSE;
}
const LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_id) const
{
for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
const LLViewerObject* attached_object = (*iter);
if (attached_object->getAttachmentItemID() == object_id)
{
return attached_object;
}
}
return NULL;
}
LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_id)
{
for (attachedobjs_vec_t::iterator iter = mAttachedObjects.begin();
iter != mAttachedObjects.end();
++iter)
{
LLViewerObject* attached_object = (*iter);
if (attached_object->getAttachmentItemID() == object_id)
{
return attached_object;
}
}
return NULL;
}

View File

@@ -82,9 +82,7 @@ public:
S32 getGroup() { return mGroup; }
S32 getPieSlice() { return mPieSlice; }
LLViewerObject *getObject() { return mAttachedObject; }
S32 getNumObjects() { return (mAttachedObject ? 1 : 0); }
const LLUUID& getItemID() { return mItemID; }
S32 getNumObjects() { return mAttachedObjects.size(); }
//
// unique methods
@@ -92,21 +90,30 @@ public:
BOOL addObject(LLViewerObject* object);
void removeObject(LLViewerObject *object);
void setupDrawable(LLDrawable* drawable);
void clampObjectPosition();
//
// attachments operations
//
BOOL isObjectAttached(const LLViewerObject *viewer_object) const;
const LLViewerObject *getAttachedObject(const LLUUID &object_id) const;
LLViewerObject *getAttachedObject(const LLUUID &object_id);
// list of attachments for this joint
typedef std::vector<LLViewerObject *> attachedobjs_vec_t;
attachedobjs_vec_t mAttachedObjects;
protected:
void calcLOD();
void setupDrawable(LLViewerObject *object);
protected:
// Backlink only; don't make this an LLPointer.
LLViewerObject* mAttachedObject;
BOOL mVisibleInFirst;
LLVector3 mOriginalPos;
S32 mGroup;
BOOL mIsHUDAttachment;
S32 mPieSlice;
LLUUID mItemID; // Inventory item id of the attached item (null if not in inventory)
};
#endif // LL_LLVIEWERJOINTATTACHMENT_H

View File

@@ -2208,7 +2208,7 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t
{
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if (attachment->getObject())
if (attachment->getNumObjects() > 0)
{
new_value = true;
break;
@@ -6636,35 +6636,46 @@ class LLAttachmentDrop : public view_listener_t
// called from avatar pie menu
void handle_detach_from_avatar(void* user_data)
{
LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;
LLViewerJointAttachment *attachment = (LLViewerJointAttachment*)user_data;
LLViewerObject* attached_object = attachment->getObject();
if (attached_object)
if (attachment->getNumObjects() > 0)
{
gMessageSystem->newMessage("ObjectDetach");
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin();
iter != attachment->mAttachedObjects.end();
iter++)
{
LLViewerObject *attached_object = (*iter);
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
}
gMessageSystem->sendReliable( gAgent.getRegionHost() );
}
}
void attach_label(std::string& label, void* user_data)
{
LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data;
if (attachmentp)
LLViewerJointAttachment *attachment = (LLViewerJointAttachment*)user_data;
if (attachment)
{
label = attachmentp->getName();
if (attachmentp->getObject())
label = attachment->getName();
for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID());
if (itemp)
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object)
{
label += std::string(" (") + itemp->getName() + std::string(")");
LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
if (itemp)
{
label += std::string(" (") + itemp->getName() + std::string(")");
break;
}
}
}
}
@@ -6672,16 +6683,23 @@ void attach_label(std::string& label, void* user_data)
void detach_label(std::string& label, void* user_data)
{
LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data;
if (attachmentp)
LLViewerJointAttachment *attachment = (LLViewerJointAttachment*)user_data;
if (attachment)
{
label = attachmentp->getName();
if (attachmentp->getObject())
label = attachment->getName();
for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID());
if (itemp)
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object)
{
label += std::string(" (") + itemp->getName() + std::string(")");
LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
if (itemp)
{
label += std::string(" (") + itemp->getName() + std::string(")");
break;
}
}
}
}
@@ -6784,23 +6802,27 @@ class LLAttachmentEnableDrop : public view_listener_t
if ( attachment_pt )
{
// make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
// so check to see if the item is in the inventory already
item = gInventory.getItem(attachment_pt->getItemID());
if ( !item )
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment_pt->mAttachedObjects.begin();
attachment_iter != attachment_pt->mAttachedObjects.end();
++attachment_iter)
{
// Item does not exist, make an observer to enable the pie menu
// when the item finishes fetching worst case scenario
// if a fetch is already out there (being sent from a slow sim)
// we refetch and there are 2 fetches
LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver();
LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched
// make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
// so check to see if the item is in the inventory already
item = gInventory.getItem((*attachment_iter)->getAttachmentItemID());
if (!item)
{
// Item does not exist, make an observer to enable the pie menu
// when the item finishes fetching worst case scenario
// if a fetch is already out there (being sent from a slow sim)
// we refetch and there are 2 fetches
LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver();
LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched
items.push_back(attachment_pt->getItemID());
wornItemFetched->fetchItems(items);
gInventory.addObserver(wornItemFetched);
items.push_back((*attachment_iter)->getAttachmentItemID());
wornItemFetched->fetchItems(items);
gInventory.addObserver(wornItemFetched);
}
}
}
}
@@ -6919,7 +6941,7 @@ BOOL object_attached(void *user_data)
{
LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;
return attachment->getObject() != NULL;
return attachment->getNumObjects() > 0;
}
class LLAvatarSendIM : public view_listener_t
@@ -7187,17 +7209,23 @@ void handle_dump_attachments(void*)
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
S32 key = curiter->first;
BOOL visible = (attachment->getObject() != NULL &&
attachment->getObject()->mDrawable.notNull() &&
!attachment->getObject()->mDrawable->isRenderType(0));
LLVector3 pos;
if (visible) pos = attachment->getObject()->mDrawable->getPosition();
llinfos << "ATTACHMENT " << key << ": item_id=" << attachment->getItemID()
<< (attachment->getObject() ? " present " : " absent ")
<< (visible ? "visible " : "invisible ")
<< " at " << pos
<< " and " << (visible ? attachment->getObject()->getPosition() : LLVector3::zero)
<< llendl;
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
LLViewerObject *attached_object = (*attachment_iter);
BOOL visible = (attached_object != NULL &&
attached_object->mDrawable.notNull() &&
!attached_object->mDrawable->isRenderType(0));
LLVector3 pos;
if (visible) pos = attached_object->mDrawable->getPosition();
llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID()
<< (attached_object ? " present " : " absent ")
<< (visible ? "visible " : "invisible ")
<< " at " << pos
<< " and " << (visible ? attached_object->getPosition() : LLVector3::zero)
<< llendl;
}
}
}

View File

@@ -203,7 +203,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mJointInfo(NULL),
mState(0),
mMedia(NULL),
mClickAction(0)
mClickAction(0),
mAttachmentItemID(LLUUID::null)
{
if(!is_global)
{
@@ -504,9 +505,20 @@ BOOL LLViewerObject::isOverGroupOwnedLand() const
&& mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion());
}
void LLViewerObject::setParent(LLViewerObject* parent)
BOOL LLViewerObject::setParent(LLViewerObject* parent)
{
LLPrimitive::setParent(parent);
if (mParent != parent)
{
LLViewerObject* old_parent = (LLViewerObject*)mParent ;
BOOL ret = LLPrimitive::setParent(parent);
if (ret && old_parent && parent)
{
old_parent->removeChild(this) ;
}
return ret ;
}
return FALSE ;
}
void LLViewerObject::addChild(LLViewerObject *childp)
@@ -525,8 +537,10 @@ void LLViewerObject::addChild(LLViewerObject *childp)
childp->mbCanSelect = mbCanSelect;
}
childp->setParent(this);
mChildList.push_back(childp);
if (childp->setParent(this))
{
mChildList.push_back(childp);
}
}
void LLViewerObject::removeChild(LLViewerObject *childp)
@@ -622,12 +636,16 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp)
{
return FALSE;
}
BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
if (!ret)
{
return FALSE ;
}
LLDrawable* old_parent = mDrawable->mParent;
mDrawable->mParent = parentp;
BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
if( (old_parent != parentp && old_parent)
|| (parentp && parentp->isActive()))
@@ -5177,3 +5195,19 @@ std::string LLViewerObject::getAttachmentPointName()
return llformat("unsupported point %d", point);
}
// </edit>
const LLUUID &LLViewerObject::extractAttachmentItemID()
{
LLUUID item_id = LLUUID::null;
LLNameValue* item_id_nv = getNVPair("AttachItemID");
if (item_id_nv)
{
const char* s = item_id_nv->getString();
if (s)
{
item_id.set(s);
}
}
setAttachmentItemID(item_id);
return getAttachmentItemID();
}

View File

@@ -236,7 +236,7 @@ public:
BOOL isProbablyModifiable() const;
*/
virtual void setParent(LLViewerObject* parent);
virtual BOOL setParent(LLViewerObject* parent);
virtual void addChild(LLViewerObject *childp);
virtual void removeChild(LLViewerObject *childp);
const_child_list_t& getChildren() const { return mChildList; }
@@ -662,6 +662,12 @@ protected:
private:
static S32 sNumObjects;
public:
const LLUUID &getAttachmentItemID() const { return mAttachmentItemID; }
void setAttachmentItemID(const LLUUID &id) { mAttachmentItemID = id; }
const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object
private:
LLUUID mAttachmentItemID; // ItemID when item is in user inventory.
// <edit>
public:
S32 getAttachmentPoint();

View File

@@ -1241,18 +1241,22 @@ void LLViewerObjectList::generatePickList(LLCamera &camera)
LLViewerJointAttachment* attachmentp = curiter->second;
if (attachmentp->getIsHUDAttachment())
{
LLViewerObject* objectp = attachmentp->getObject();
if (objectp)
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachmentp->mAttachedObjects.begin();
attachment_iter != attachmentp->mAttachedObjects.end();
++attachment_iter)
{
mSelectPickList.insert(objectp);
LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
if (LLViewerObject* objectp = (*attachment_iter))
{
LLViewerObject* childp = *iter;
if (childp)
mSelectPickList.insert(objectp);
LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
{
mSelectPickList.insert(childp);
LLViewerObject* childp = *iter;
if (childp)
{
mSelectPickList.insert(childp);
}
}
}
}

View File

@@ -1635,27 +1635,32 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
continue ;
}
LLViewerObject* object = attachment->getObject();
if (object && !object->isHUDAttachment())
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
LLDrawable* drawable = object->mDrawable;
if (drawable)
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object && !attached_object->isHUDAttachment())
{
LLSpatialBridge* bridge = drawable->getSpatialBridge();
if (bridge)
LLDrawable* drawable = attached_object->mDrawable;
if (drawable)
{
const LLVector3* ext = bridge->getSpatialExtents();
LLVector3 distance = (ext[1] - ext[0]);
// Only add the prim to spatial extents calculations if it isn't a megaprim.
// max_attachment_span calculated at the start of the function
// (currently 5 times our max prim size)
if (distance.mV[0] < max_attachment_span
&& distance.mV[1] < max_attachment_span
&& distance.mV[2] < max_attachment_span)
LLSpatialBridge* bridge = drawable->getSpatialBridge();
if (bridge)
{
update_min_max(newMin,newMax,ext[0]);
update_min_max(newMin,newMax,ext[1]);
const LLVector3* ext = bridge->getSpatialExtents();
LLVector3 distance = (ext[1] - ext[0]);
// Only add the prim to spatial extents calculations if it isn't a megaprim.
// max_attachment_span calculated at the start of the function
// (currently 5 times our max prim size)
if (distance.mV[0] < max_attachment_span
&& distance.mV[1] < max_attachment_span
&& distance.mV[2] < max_attachment_span)
{
update_min_max(newMin,newMax,ext[0]);
update_min_max(newMin,newMax,ext[1]);
}
}
}
}
@@ -2867,30 +2872,32 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
LLViewerObject *attached_object = attachment->getObject();
BOOL visibleAttachment = visible || (attached_object &&
!(attached_object->mDrawable->getSpatialBridge() &&
attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
// if selecting any attachments, update all of them as non-damped
if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment())
{
gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
LLViewerObject* attached_object = (*attachment_iter);
BOOL visibleAttachment = visible || (attached_object &&
!(attached_object->mDrawable->getSpatialBridge() &&
attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
{
// if selecting any attachments, update all of them as non-damped
if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment())
{
gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
}
else
{
gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
}
LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
if (bridge)
{
gPipeline.updateMoveNormalAsync(bridge);
}
attached_object->updateText();
}
else
{
gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
}
LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
if (bridge)
{
gPipeline.updateMoveNormalAsync(bridge);
}
attached_object->updateText();
}
}
}
@@ -4727,19 +4734,24 @@ void LLVOAvatar::updateVisibility()
/*llinfos << "SPA: " << sel_pos_agent << llendl;
llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
iter != mAttachmentPoints.end(); iter++)
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if (attachment->getObject())
LLViewerJointAttachment* attachment = iter->second;
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
if(attachment->getObject()->mDrawable->isVisible())
if (LLViewerObject *attached_object = (*attachment_iter))
{
llinfos << attachment->getName() << " visible" << llendl;
}
else
{
llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl;
if (attached_object->mDrawable->isVisible())
{
llinfos << attachment->getName() << " visible" << llendl;
}
else
{
llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl;
}
}
}
}
@@ -6882,12 +6894,13 @@ void LLVOAvatar::requestLayerSetUpdate(ETextureIndex index )
}
}
void LLVOAvatar::setParent(LLViewerObject* parent)
BOOL LLVOAvatar::setParent(LLViewerObject* parent)
{
BOOL ret ;
if (parent == NULL)
{
getOffObject();
LLViewerObject::setParent(parent);
ret = LLViewerObject::setParent(parent);
if (isSelf())
{
gAgent.resetCamera();
@@ -6895,13 +6908,18 @@ void LLVOAvatar::setParent(LLViewerObject* parent)
}
else
{
LLViewerObject::setParent(parent);
sitOnObject(parent);
}
ret = LLViewerObject::setParent(parent);
if (ret)
{
sitOnObject(parent);
}
}
return ret ;
}
void LLVOAvatar::addChild(LLViewerObject *childp)
{
childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
LLViewerObject::addChild(childp);
if (childp->mDrawable)
{
@@ -6923,11 +6941,20 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi
{
S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
// This should never happen unless the server didn't process the attachment point
// correctly, but putting this check in here to be safe.
if (attachmentID & ATTACHMENT_ADD)
{
llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl;
attachmentID &= ~ATTACHMENT_ADD;
}
LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
if (!attachment)
{
llwarns << "Object attachment point invalid: " << attachmentID << llendl;
attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest)
}
return attachment;
@@ -6966,7 +6993,7 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object)
updateAttachmentVisibility(gAgent.getCameraMode());
// Then make sure the inventory is in sync with the avatar.
gInventory.addChangedMask( LLInventoryObserver::LABEL, item_id );
gInventory.addChangedMask(LLInventoryObserver::LABEL, viewer_object->getAttachmentItemID());
gInventory.notifyObservers();
}
}
@@ -6990,13 +7017,34 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object)
updateAttachmentVisibility(gAgent.getCameraMode());
// Then make sure the inventory is in sync with the avatar.
gInventory.addChangedMask( LLInventoryObserver::LABEL, attachment->getItemID() );
gInventory.addChangedMask(LLInventoryObserver::LABEL, viewer_object->getAttachmentItemID());
gInventory.notifyObservers();
}
return TRUE;
}
U32 LLVOAvatar::getNumAttachments() const
{
U32 num_attachments = 0;
for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment *attachment_pt = (*iter).second;
num_attachments += attachment_pt->getNumObjects();
}
return num_attachments;
}
//-----------------------------------------------------------------------------
// canAttachMoreObjects()
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::canAttachMoreObjects() const
{
return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
}
//-----------------------------------------------------------------------------
// lazyAttach()
//-----------------------------------------------------------------------------
@@ -7022,16 +7070,20 @@ void LLVOAvatar::lazyAttach()
void LLVOAvatar::resetHUDAttachments()
{
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
iter != mAttachmentPoints.end(); iter++)
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getIsHUDAttachment())
{
LLViewerObject* obj = attachment->getObject();
if (obj && obj->mDrawable.notNull())
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
gPipeline.markMoved(obj->mDrawable);
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object && attached_object->mDrawable.notNull())
{
gPipeline.markMoved(attached_object->mDrawable);
}
}
}
}
@@ -7048,9 +7100,9 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
// only one object per attachment point for now
if (attachment->getObject() == viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
LLUUID item_id = attachment->getItemID();
LLUUID item_id = viewer_object->getAttachmentItemID();
attachment->removeObject(viewer_object);
if (mIsSelf)
{
@@ -7315,14 +7367,15 @@ LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj )
//-----------------------------------------------------------------------------
// isWearingAttachment()
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::isWearingAttachment( const LLUUID& inv_item_id )
BOOL LLVOAvatar::isWearingAttachment(const LLUUID& inv_item_id)
{
const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if( attachment->getItemID() == inv_item_id )
if(attachment->getAttachedObject(base_inv_item_id))
{
return TRUE;
}
@@ -7346,16 +7399,17 @@ BOOL LLVOAvatar::isWearingUnsupportedAttachment( const LLUUID& inv_item_id )
//-----------------------------------------------------------------------------
// getWornAttachment()
//-----------------------------------------------------------------------------
LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id )
LLViewerObject* LLVOAvatar::getWornAttachment(const LLUUID& inv_item_id)
{
const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if( attachment->getItemID() == inv_item_id )
if (LLViewerObject *attached_object = attachment->getAttachedObject(base_inv_item_id))
{
return attachment->getObject();
return attached_object;
}
}
return NULL;
@@ -7363,12 +7417,13 @@ LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id )
const std::string LLVOAvatar::getAttachedPointName(const LLUUID& inv_item_id)
{
const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if( attachment->getItemID() == inv_item_id )
if (attachment->getAttachedObject(base_inv_item_id))
{
return attachment->getName();
}
@@ -8901,11 +8956,10 @@ void LLVOAvatar::clampAttachmentPositions()
BOOL LLVOAvatar::hasHUDAttachment() const
{
for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
iter != mAttachmentPoints.end(); ++iter)
{
attachment_map_t::const_iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if (attachment->getIsHUDAttachment() && attachment->getObject())
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0)
{
return TRUE;
}
@@ -8917,24 +8971,33 @@ LLBBox LLVOAvatar::getHUDBBox() const
{
LLBBox bbox;
for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
iter != mAttachmentPoints.end(); ++iter)
{
attachment_map_t::const_iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if (attachment->getIsHUDAttachment() && attachment->getObject())
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getIsHUDAttachment())
{
LLViewerObject* hud_object = attachment->getObject();
// initialize bounding box to contain identity orientation and center point for attached object
bbox.addPointLocal(hud_object->getPosition());
// add rotated bounding box for attached object
bbox.addBBoxAgent(hud_object->getBoundingBoxAgent());
LLViewerObject::const_child_list_t& child_list = hud_object->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
LLViewerObject* child_objectp = *iter;
bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent());
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object == NULL)
{
llwarns << "HUD attached object is NULL!" << llendl;
continue;
}
// initialize bounding box to contain identity orientation and center point for attached object
bbox.addPointLocal(attached_object->getPosition());
// add rotated bounding box for attached object
bbox.addBBoxAgent(attached_object->getBoundingBoxAgent());
LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end();
++iter)
{
const LLViewerObject* child_objectp = *iter;
bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent());
}
}
}
}
@@ -10367,20 +10430,25 @@ void LLVOAvatar::idleUpdateRenderCost()
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
LLViewerObject* object = attachment->getObject();
if (object && !object->isHUDAttachment())
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
LLDrawable* drawable = object->mDrawable;
if (drawable)
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object && !attached_object->isHUDAttachment())
{
shame += 10;
LLVOVolume* volume = drawable->getVOVolume();
if (volume)
const LLDrawable* drawable = attached_object->mDrawable;
if (drawable)
{
shame += calc_shame(volume, textures);
}
}
}
shame += 10;
LLVOVolume* volume = drawable->getVOVolume();
if (volume)
{
shame += calc_shame(volume, textures);
}
}
}
}
}
if(sDoProperArc)

View File

@@ -155,6 +155,7 @@ public:
void updateAttachmentVisibility(U32 camera_mode);
void clampAttachmentPositions();
S32 getAttachmentCount(); // Warning: order(N) not order(1)
BOOL canAttachMoreObjects() const;
// HUD functions
BOOL hasHUDAttachment() const;
@@ -292,7 +293,7 @@ public:
void hideSkirt();
virtual void setParent(LLViewerObject* parent);
virtual BOOL setParent(LLViewerObject* parent);
virtual void addChild(LLViewerObject *childp);
virtual void removeChild(LLViewerObject *childp);
@@ -587,7 +588,8 @@ public:
// <edit>
std::map<S32, LLUUID> mUnsupportedAttachmentPoints;
// </edit>
protected:
U32 getNumAttachments() const; // O(N), not O(1) <---- Fix if possible, I guess it's not worst case scenario - HgB
//--------------------------------------------------------------------
// static preferences that are controlled by user settings/menus
//--------------------------------------------------------------------

View File

@@ -881,17 +881,19 @@ void LLVOVolume::updateFaceFlags()
}
}
void LLVOVolume::setParent(LLViewerObject* parent)
BOOL LLVOVolume::setParent(LLViewerObject* parent)
{
BOOL ret = FALSE;
if (parent != getParent())
{
LLViewerObject::setParent(parent);
ret = LLViewerObject::setParent(parent);
if (mDrawable)
{
gPipeline.markMoved(mDrawable);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
}
}
return ret;
}
// NOTE: regenFaces() MUST be followed by genTriangles()!

View File

@@ -105,7 +105,7 @@ public:
/*virtual*/ BOOL isHUDAttachment() const;
void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point);
/*virtual*/ void setParent(LLViewerObject* parent);
/*virtual*/ BOOL setParent(LLViewerObject* parent);
S32 getLOD() const { return mLOD; }
const LLVector3 getPivotPositionAgent() const;
const LLMatrix4& getRelativeXform() const { return mRelativeXform; }

View File

@@ -3344,39 +3344,41 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects, BOOL render
LLViewerJointAttachment* attachmentp = curiter->second;
if (attachmentp->getIsHUDAttachment())
{
LLViewerObject* objectp = attachmentp->getObject();
if (objectp)
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachmentp->mAttachedObjects.begin();
attachment_iter != attachmentp->mAttachedObjects.end();
++attachment_iter)
{
LLDrawable* drawable = objectp->mDrawable;
if (drawable->isDead())
if (LLViewerObject* objectp = (*attachment_iter))
{
continue;
}
for (S32 j = 0; j < drawable->getNumFaces(); ++j)
{
LLFace* facep = drawable->getFace(j);
if (!facep->getPool())
LLDrawable* drawable = objectp->mDrawable;
if (drawable->isDead())
{
facep->renderForSelect(prim_mask);
continue;
}
}
//render child faces
LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
{
LLViewerObject* child = *iter;
LLDrawable* child_drawable = child->mDrawable;
for (S32 l = 0; l < child_drawable->getNumFaces(); ++l)
for (S32 j = 0; j < drawable->getNumFaces(); ++j)
{
LLFace* facep = child_drawable->getFace(l);
LLFace* facep = drawable->getFace(j);
if (!facep->getPool())
{
facep->renderForSelect(prim_mask);
}
}
//render child faces
LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
iter != child_list.end(); iter++)
{
LLViewerObject* child = *iter;
LLDrawable* child_drawable = child->mDrawable;
for (S32 l = 0; l < child_drawable->getNumFaces(); ++l)
{
LLFace* facep = child_drawable->getFace(l);
if (!facep->getPool())
{
facep->renderForSelect(prim_mask);
}
}
}
}
}
}
@@ -4846,7 +4848,7 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
void LLPipeline::resetVertexBuffers()
{
sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("ShyotlRenderUseStreamVBO");
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
{
@@ -6508,10 +6510,15 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
iter != avatar->mAttachmentPoints.end();
++iter)
{
LLViewerObject* object = iter->second->getObject();
if (object)
LLViewerJointAttachment *attachment = iter->second;
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
markVisible(object->mDrawable->getSpatialBridge(), *LLViewerCamera::getInstance());
if (LLViewerObject* attached_object = (*attachment_iter))
{
markVisible(attached_object->mDrawable->getSpatialBridge(), *LLViewerCamera::getInstance());
}
}
}

View File

@@ -170,11 +170,16 @@ void ScriptCounter::serializeSelection(bool delScript)
LLViewerJointAttachment* attachment = iter->second;
if (!attachment->getValid())
continue ;
LLViewerObject* object = attachment->getObject();
if(object)
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
objectArray.put(object);
objectCount++;
LLViewerObject *attached_object = (*attachment_iter);
if (attached_object)
{
objectArray.put(attached_object);
objectCount++;
}
}
}
}

View File

@@ -24,6 +24,10 @@
<check_box bottom="-456" enabled="true" follows="left|top" font="SansSerifSmall"
height="16" initial_value="false" label="Rename Clothing To Folder Name"
left="13" mouse_opaque="true" name="rename" radio_style="false" width="210" />
<check_box name="checkbox_use_links" control_name="UseInventoryLinks" initial_value="false"
enabled="true" label="Use links for no-copy items" font="SansSerifSmall"
bottom_delta="-20" left_delta="0" follows="left|top" height="16" width="300"
mouse_opaque="true" radio_style="false" />
<check_box bottom="-216" enabled="true" follows="left|top" font="SansSerifSmall"
height="16" initial_value="false" label="Shirt" left="113"
mouse_opaque="true" name="checkbox_Shirt" radio_style="false" width="100" />

View File

@@ -129,6 +129,10 @@
name="Sound Open" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="open" />
</menu_item_call>
<menu_item_call bottom_delta="-18" height="18" label="Find Original" left="0"
mouse_opaque="true" name="Find Original" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="goto" />
</menu_item_call>
<menu_item_call bottom_delta="-18" height="18" label="Purge Item" left="0" mouse_opaque="true"
name="Purge Item" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="purge" />
@@ -186,6 +190,10 @@
name="Paste" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="paste" />
</menu_item_call>
<menu_item_call bottom_delta="-18" height="18" label="Paste As Link" left="0" mouse_opaque="true"
name="Paste As Link" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="paste_link" />
</menu_item_call>
<menu_item_separator name="Paste Separator" />
<menu_item_call bottom_delta="-18" height="18" label="Delete" left="0" mouse_opaque="true"
name="Delete" width="128">
@@ -251,10 +259,6 @@
<on_click filter="" function="Inventory.DoToSelected" userdata="deactivate" />
</menu_item_call>
<menu_item_separator name="Attach Separator" />
<menu_item_call bottom_delta="-18" height="18" label="Detach From Yourself" left="0"
mouse_opaque="true" name="Detach From Yourself" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="detach" />
</menu_item_call>
<!-- COMMENTED OUT for DEV-32347 -->
<menu_item_call bottom_delta="-18" height="18" label="Restore to Last Position" left="0" mouse_opaque="true"
name="Restore to Last Position" width="128">
@@ -264,11 +268,19 @@
name="Object Wear" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="attach" />
</menu_item_call>
<menu_item_call bottom_delta="-18" height="18" label="Add" left="0" mouse_opaque="true"
name="Object Add" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="wear_add" />
</menu_item_call>
<menu bottom_delta="-18" height="18" label="Attach To" left="0" mouse_opaque="true"
name="Attach To" opaque="true" tear_off="false" width="128" />
<menu bottom_delta="-18" height="18" label="Attach To HUD" left="0"
mouse_opaque="true" name="Attach To HUD" opaque="true" tear_off="false"
width="128" />
<menu_item_call bottom_delta="-18" height="18" label="Detach From Yourself" left="0"
mouse_opaque="true" name="Detach From Yourself" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="detach" />
</menu_item_call>
<menu_item_call bottom_delta="-18" height="18" label="Edit" left="0" mouse_opaque="true"
name="Wearable Edit" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="edit" />

View File

@@ -798,6 +798,14 @@ The outfit folder contains no clothing, body parts, or attachments.
You can not wear clothes or body parts that are in the trash
</notification>
<notification
icon="alertmodal.tga"
name="MaxAttachmentsOnOutfit"
type="alertmodal">
Could not attach object.
Exceeds the attachments limit of [MAX_ATTACHMENTS] objects. Please detach another object first.
</notification>
<notification
icon="alertmodal.tga"
name="CannotWearInfoNotComplete"

View File

@@ -142,6 +142,10 @@
can_apply_immediately="true" color="0.8 1 1 1" mouse_opaque="true"
enabled="true" follows="left|top" height="47" label="Muted" left_delta="54"
name="muted_color_swatch" width="44" />
<color_swatch border_color="0.45098 0.517647 0.607843 1" bottom_delta="0"
can_apply_immediately="true" color="0.8 1 1 1" mouse_opaque="true"
enabled="true" follows="left|top" height="47" label="Muted" left_delta="54"
name="custom_color_swatch" width="44" />
</panel>
<panel border="true" left="1" bottom="-190" height="180" width="500" mouse_opaque="true"
follows="left|top|right|bottom" label="Body Dynamics" name="Body Dynamics">

View File

@@ -8934,3 +8934,24 @@ version 2.0
{ CRC U32 }
}
}
// Link inventory
{
LinkInventoryItem Low 426 NotTrusted Zerocoded
{
AgentData Single
{ AgentID LLUUID }
{ SessionID LLUUID }
}
{
InventoryBlock Single
{ CallbackID U32 } // Async Response
{ FolderID LLUUID }
{ TransactionID LLUUID } // Going to become TransactionID
{ OldItemID LLUUID }
{ Type S8 }
{ InvType S8 }
{ Name Variable 1 }
{ Description Variable 1 }
}
}