First attempt to deal with broken (pre multiwear) inventory items.
Since multiwear, the low 8 bit of inventory items, if they are of type IT_WEARABLE, is used for the wearable type (WT_*). Older viewers and bots (like Second Inventory) create inventory items with 0 in those bits. This causes all those item to appear as shapes in multi-wear capable viewers. This gives rise to many problems: 1) You can't wear them, because the inventory and asset wearable type mismatch, which makes Singularity just abort. 2) Before it aborts, it already removed your old shape, thinking you are about to wear another shape - and told the server that you are wearing this broken item now. The result is that you see no change, until you relog when you are suddenly wearing the broken "shape" and stay a cloud forever. This commit detects the problem for AT_CLOTHING wearables, because they are not compatible with the type 'shape' after all (which is is AT_BODYPART). It still doesn't know what the wearable type is, but sets the type temporarily to the new value WT_UNKNOWN. Since this is at least not a shape anymore, it doesn't cause you shape to be removed when wearing it. Moreover, once the asset is downloaded, the mismatch is detected and corrected: you can now wear -say- pants, or other clothing. Inventory clothing items with an unknown wearable type now have a red question mark icon in the inventory. What does NOT work yet: 1) If you copy such an item and paste it, then the new copy has a shape icon again (and all the previously mentioned problems). 2) If you wear broken hair, skin or eyes (which still show as shapes in the inventory) then your shape is still removed, and wearing them fails because they are not multiwear capable and you are already wearing such a body part. What should be done here is that the removed shape is added back and the real body part that you're trying to wear is removed. 3) Although this code attempts to fix the mFlags in the inventory, the icon in the inventory doesn't change from question mark to the right thing.
This commit is contained in:
@@ -104,6 +104,7 @@ LLWearableDictionary::LLWearableDictionary()
|
||||
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
|
||||
// [/SL:KB]
|
||||
|
||||
addEntry(LLWearableType::WT_UNKNOWN, new WearableEntry("unknown", "Clothing", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNKNOWN, FALSE, TRUE));
|
||||
addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
|
||||
addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
|
||||
}
|
||||
|
||||
@@ -61,7 +61,10 @@ public:
|
||||
WT_ALPHA = 13,
|
||||
WT_TATTOO = 14,
|
||||
WT_PHYSICS = 15,
|
||||
WT_COUNT = 16,
|
||||
WT_UNKNOWN = 16, // Singu note: used for corrupt wearables that do not have their type set in the inventory database.
|
||||
// While all the above values are serialized and stored in the database, this value is local only:
|
||||
// When a new item with value 16 is added by upstream, just increase this value to 17 (and WT_COUNT to 18).
|
||||
WT_COUNT = 17,
|
||||
|
||||
WT_INVALID = 255,
|
||||
WT_NONE = -1,
|
||||
|
||||
@@ -1150,6 +1150,40 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
mFlags = sd[w].asInteger();
|
||||
}
|
||||
|
||||
//<singu>
|
||||
// Define a few magic constants that are not accessible otherwise, from here.
|
||||
// mInventoryType:
|
||||
static U32 IT_WEARABLE = 18; // LLInventoryType::IT_WEARABLE
|
||||
// mType, these are the two asset types that are IT_WEARABLE:
|
||||
static U32 AT_BODYPART = 13; // LLAssetType::AT_BODYPART
|
||||
// Viewer local values:
|
||||
static U32 WT_UNKNOWN = 16; // LLWearableType::WT_UNKNOWN
|
||||
static U32 WT_COUNT = 17; // LLWearableType::WT_COUNT
|
||||
// The last 8 bits of mFlags contain the wearable type.
|
||||
static U32 II_FLAGS_WEARABLES_MASK = 0xff; // LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK
|
||||
|
||||
// The wearable type is stored in the lower 8 bits of mFlags.
|
||||
U32 wt = mFlags & II_FLAGS_WEARABLES_MASK;
|
||||
|
||||
// Because WT_UNKNOWN now has locally a special meaning, make sure we don't receive it from the server.
|
||||
if (wt == WT_UNKNOWN)
|
||||
{
|
||||
llwarns << "Received inventory item with wearable type WT_UNKNOWN from server! You should upgrade your viewer." << llendl;
|
||||
// Change this new wearable type to WT_COUNT, as if when we had not inserted WT_UNKNOWN locally.
|
||||
mFlags += 1;
|
||||
wt = WT_COUNT;
|
||||
}
|
||||
|
||||
// Detect possible problematic items.
|
||||
if (wt == 0 && mInventoryType == IT_WEARABLE && mType != AT_BODYPART)
|
||||
{
|
||||
// This is not possible, and therefore is probably an item creatd by a pre-multiwear viewer (or Second Inventory, etc).
|
||||
// The wearable type is NOT a shape (0) in that case of course, but we don't know what it is without downloading the
|
||||
// asset.
|
||||
mFlags |= WT_UNKNOWN;
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
w = INV_NAME_LABEL;
|
||||
if (sd.has(w))
|
||||
|
||||
@@ -108,6 +108,7 @@ public:
|
||||
ICONNAME_LINKFOLDER,
|
||||
ICONNAME_MESH,
|
||||
|
||||
ICONNAME_CLOTHING_UNKNOWN,
|
||||
ICONNAME_INVALID,
|
||||
ICONNAME_COUNT,
|
||||
ICONNAME_NONE = -1
|
||||
|
||||
@@ -1163,11 +1163,41 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)
|
||||
if(wearable->getAssetID() == data.mAssetID)
|
||||
{
|
||||
// Failing this means inventory or asset server are corrupted in a way we don't handle.
|
||||
if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType))
|
||||
if (data.mWearableType >= LLWearableType::WT_COUNT ||
|
||||
wearable->getType() >= LLWearableType::WT_UNKNOWN ||
|
||||
(data.mWearableType != wearable->getType() &&
|
||||
data.mWearableType != LLWearableType::WT_UNKNOWN &&
|
||||
data.mWearableType != LLWearableType::WT_SHAPE))
|
||||
{
|
||||
llwarns << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl;
|
||||
break;
|
||||
}
|
||||
else if (data.mWearableType == LLWearableType::WT_UNKNOWN ||
|
||||
(data.mWearableType == LLWearableType::WT_SHAPE &&
|
||||
data.mWearableType != wearable->getType()))
|
||||
{
|
||||
if (data.mWearableType == LLWearableType::WT_UNKNOWN)
|
||||
{
|
||||
llinfos << "Wearing wearable '" << wearable->getName() << "' with an unknown inventory wearable type. Fixing inventory to have type " << wearable->getType() << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This probably means that the inventory contains an item without wearable type information.
|
||||
// We can still fix the type here, but we also have to fix that in the mean time we took off our real shape because of this!
|
||||
llwarns << "Wearing wearable '" << wearable->getName() << "' with incorrect wearable type 'shape'! Trying to recover from this..." << llendl;
|
||||
}
|
||||
// Fix it!
|
||||
data.mWearableType = wearable->getType();
|
||||
LLViewerInventoryItem* item = gInventory.getItem(data.mItemID);
|
||||
if (!item)
|
||||
{
|
||||
llwarns << "Can't find the broken item in the inventory?!" << llendl;
|
||||
break;
|
||||
}
|
||||
llassert(item->getUUID() == data.mItemID);
|
||||
item->setWearableType(wearable->getType());
|
||||
gInventory.updateItem(item);
|
||||
}
|
||||
|
||||
data.mWearable = wearable;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ LLIconDictionary::LLIconDictionary()
|
||||
addEntry(LLInventoryType::ICONNAME_LINKFOLDER, new IconEntry("inv_link_folder.tga"));
|
||||
addEntry(LLInventoryType::ICONNAME_MESH, new IconEntry("inv_item_mesh.tga"));
|
||||
|
||||
addEntry(LLInventoryType::ICONNAME_CLOTHING_UNKNOWN, new IconEntry("inv_item_unknown.tga"));
|
||||
addEntry(LLInventoryType::ICONNAME_INVALID, new IconEntry("inv_invalid.png"));
|
||||
|
||||
addEntry(LLInventoryType::ICONNAME_NONE, new IconEntry("NONE"));
|
||||
|
||||
@@ -311,6 +311,12 @@ void LLViewerInventoryItem::removeFromServer()
|
||||
|
||||
void LLViewerInventoryItem::updateServer(BOOL is_new) const
|
||||
{
|
||||
if(getWearableType() == LLWearableType::WT_UNKNOWN)
|
||||
{
|
||||
llwarns << "LLViewerInventoryItem::updateServer() - for item with unknown wearable type"
|
||||
<< llendl;
|
||||
return;
|
||||
}
|
||||
if(!mIsComplete)
|
||||
{
|
||||
// *FIX: deal with this better.
|
||||
@@ -1777,6 +1783,15 @@ LLWearableType::EType LLViewerInventoryItem::getWearableType() const
|
||||
return LLWearableType::EType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
|
||||
}
|
||||
|
||||
void LLViewerInventoryItem::setWearableType(LLWearableType::EType type)
|
||||
{
|
||||
if (getWearableType() != LLWearableType::WT_UNKNOWN)
|
||||
{
|
||||
llwarns << "Calling LLViewerInventoryItem::setWearableType for item that does not have an unknown wearable type!?" << llendl;
|
||||
return;
|
||||
}
|
||||
mFlags = (mFlags & ~LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK) | type;
|
||||
}
|
||||
|
||||
time_t LLViewerInventoryItem::getCreationDate() const
|
||||
{
|
||||
|
||||
@@ -162,6 +162,11 @@ public:
|
||||
// If this is a broken link, try to fix it and any other identical link.
|
||||
BOOL regenerateLink();
|
||||
|
||||
//<singu>
|
||||
// Change WT_UNKNOWN to the type retrieved from the asset.
|
||||
void setWearableType(LLWearableType::EType type);
|
||||
//</singu>
|
||||
|
||||
public:
|
||||
BOOL mIsComplete;
|
||||
LLTransactionID mTransactionID;
|
||||
|
||||
BIN
indra/newview/skins/default/textures/inv_item_unknown.tga
Normal file
BIN
indra/newview/skins/default/textures/inv_item_unknown.tga
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Reference in New Issue
Block a user