RLVa impl updated to that used in v3. Hooked RLVa restrictions back into wearables. New RLVa floater: 'Locks...' Also updated 'Restrictions...' floater.

This commit is contained in:
Shyotl
2012-04-12 10:29:45 -05:00
parent 7774fe7f04
commit b49ad1cd34
101 changed files with 4600 additions and 2635 deletions

View File

@@ -227,7 +227,7 @@
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewerwindow.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
#include "llvolume.h"
#include "llweb.h"
#include "llworld.h"
@@ -267,6 +267,8 @@ using namespace LLVOAvatarDefines;
void init_client_menu(LLMenuGL* menu);
void init_server_menu(LLMenuGL* menu);
typedef LLPointer<LLViewerObject> LLViewerObjectPtr;
void init_debug_world_menu(LLMenuGL* menu);
void init_debug_rendering_menu(LLMenuGL* menu);
void init_debug_ui_menu(LLMenuGL* menu);
@@ -275,6 +277,7 @@ void init_debug_avatar_menu(LLMenuGL* menu);
// [RLVa:KB]
#include "rlvhandler.h"
#include "rlvfloaterbehaviour.h"
#include "rlvlocks.h"
void init_debug_rlva_menu(LLMenuGL* menu);
// [/RLVa:KB]
@@ -1186,7 +1189,7 @@ void init_client_menu(LLMenuGL* menu)
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-1.0.0e | OK
#ifdef RLV_ADVANCED_TOGGLE_RLVA
if (gSavedSettings.controlExists(RLV_SETTING_MAIN))
menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvToggleEnabled, NULL, &rlvGetEnabled, NULL));
menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvMenuToggleEnabled, NULL, &rlvMenuCheckEnabled, NULL));
#endif // RLV_ADVANCED_TOGGLE_RLVA
// [/RLVa:KB]
@@ -1725,7 +1728,8 @@ void init_debug_rlva_menu(LLMenuGL* menu)
#ifdef RLV_EXTENSION_FLOATER_RESTRICTIONS
// TODO-RLVa: figure out a way to tell if floater_rlv_behaviour.xml exists
menu->addChild(new LLMenuItemCallGL("Restrictions...", RlvFloaterBehaviour::show, NULL, NULL));
menu->addChild(new LLMenuItemCheckGL("Restrictions...", &RlvFloaterBehaviours::toggle, NULL, &RlvFloaterBehaviours::visible, NULL));
menu->addChild(new LLMenuItemCheckGL("Locks...", &RlvFloaterLocks::toggle, NULL, &RlvFloaterLocks::visible, NULL));
#endif // RLV_EXTENSION_FLOATER_RESTRICTIONS
}
// [/RLVa:KB]
@@ -2482,11 +2486,10 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
bool new_value = false;
if (gAgentAvatarp)
if (isAgentAvatarValid())
{
LLVOAvatar* avatarp = gAgentAvatarp;
for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
iter != avatarp->mAttachmentPoints.end(); )
for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
iter != gAgentAvatarp->mAttachmentPoints.end(); )
{
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
@@ -4582,22 +4585,21 @@ void handle_show_overlay_title(void*)
gSavedSettings.setBOOL("ShowOverlayTitle", gShowOverlayTitle);
}
void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
static bool get_derezzable_objects(
EDeRezDestination dest,
std::string& error,
LLViewerRegion*& first_region,
LLDynamicArray<LLViewerObjectPtr>* derez_objectsp,
bool only_check = false)
{
if(gAgentCamera.cameraMouselook())
{
gAgentCamera.changeCameraToDefault();
}
//gInventoryView->setPanelOpen(TRUE);
bool found = false;
std::string error;
LLDynamicArray<LLViewerObject*> derez_objects;
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
// Check conditions that we can't deal with, building a list of
// everything that we'll actually be derezzing.
LLViewerRegion* first_region = NULL;
for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin();
iter != selection->valid_root_end(); iter++)
{
LLSelectNode* node = *iter;
LLViewerObject* object = node->getObject();
@@ -4667,10 +4669,55 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
}
if(can_derez_current)
{
derez_objects.put(object);
found = true;
if (only_check)
// one found, no need to traverse to the end
break;
if (derez_objectsp)
derez_objectsp->put(object);
}
}
return found;
}
static bool can_derez(EDeRezDestination dest)
{
LLViewerRegion* first_region = NULL;
std::string error;
return get_derezzable_objects(dest, error, first_region, NULL, true);
}
static void derez_objects(
EDeRezDestination dest,
const LLUUID& dest_id,
LLViewerRegion*& first_region,
std::string& error,
LLDynamicArray<LLViewerObjectPtr>* objectsp)
{
LLDynamicArray<LLViewerObjectPtr> derez_objects;
if (!objectsp) // if objects to derez not specified
{
// get them from selection
if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false))
{
llwarns << "No objects to derez" << llendl;
return;
}
objectsp = &derez_objects;
}
if(gAgentCamera.cameraMouselook())
{
gAgentCamera.changeCameraToDefault();
}
// This constant is based on (1200 - HEADER_SIZE) / 4 bytes per
// root. I lopped off a few (33) to provide a bit
// pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs.
@@ -4678,13 +4725,13 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
// satisfy anybody.
const S32 MAX_ROOTS_PER_PACKET = 250;
const S32 MAX_PACKET_COUNT = 254;
F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET);
F32 packets = ceil((F32)objectsp->count() / (F32)MAX_ROOTS_PER_PACKET);
if(packets > (F32)MAX_PACKET_COUNT)
{
error = "AcquireErrorTooManyObjects";
}
if(error.empty() && derez_objects.count() > 0)
if(error.empty() && objectsp->count() > 0)
{
U8 d = (U8)dest;
LLUUID tid;
@@ -4709,11 +4756,11 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
msg->addU8Fast(_PREHASH_PacketCount, packet_count);
msg->addU8Fast(_PREHASH_PacketNumber, packet_number);
objects_in_packet = 0;
while((object_index < derez_objects.count())
while((object_index < objectsp->count())
&& (objects_in_packet++ < MAX_ROOTS_PER_PACKET))
{
LLViewerObject* object = derez_objects.get(object_index++);
LLViewerObject* object = objectsp->get(object_index++);
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
// <edit>
@@ -4741,19 +4788,31 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
}
else if(!error.empty())
{
LLNotifications::instance().add(error);
LLNotificationsUtil::add(error);
}
}
static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
{
LLViewerRegion* first_region = NULL;
std::string error;
derez_objects(dest, dest_id, first_region, error, NULL);
}
class LLToolsTakeCopy : public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
// [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b | OK
// NOTE: we need to handle "Take Copy" because it will force a sim-side unsit if we're sitting on the selection,
// but we do want to allow "Take Copy" under @rez=n so that's why we explicitly check for @unsit=n here
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (!rlvCanDeleteOrReturn()) ) return true;
// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) )
{
// Allow only if the avie isn't sitting on any of the selected objects
LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
RlvSelectIsSittingOn f(gAgentAvatarp);
if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) )
return true;
}
// [/RLVa:KB]
const LLUUID& category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
@@ -4763,10 +4822,11 @@ class LLToolsTakeCopy : public view_listener_t
}
};
// You can return an object to its owner if it is on your land.
class LLObjectReturn : public view_listener_t
{
public:
LLObjectReturn() : mFirstRegion(NULL) {}
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
@@ -4776,26 +4836,36 @@ class LLObjectReturn : public view_listener_t
mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
// Save selected objects, so that we still know what to return after the confirmation dialog resets selection.
get_derezzable_objects(DRD_RETURN_TO_OWNER, mError, mFirstRegion, &mReturnableObjects);
LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2));
return true;
}
bool onReturnToOwner(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotification::getSelectedOption(notification, response);
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (0 == option)
{
// Ignore category ID for this derez destination.
derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null);
derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, mFirstRegion, mError, &mReturnableObjects);
}
mReturnableObjects.clear();
mError.clear();
mFirstRegion = NULL;
// drop reference to current selection
mObjectSelection = NULL;
return false;
}
protected:
LLObjectSelectionHandle mObjectSelection;
LLDynamicArray<LLViewerObjectPtr> mReturnableObjects;
std::string mError;
LLViewerRegion* mFirstRegion;
};
@@ -4805,6 +4875,17 @@ class LLObjectEnableReturn : public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
{
// Do not enable if nothing selected
return false;
}
// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a
if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) )
{
return false;
}
// [/RLVa:KB]
#ifdef HACKED_GODLIKE_VIEWER
bool new_value = true;
#else
@@ -4815,34 +4896,9 @@ class LLObjectEnableReturn : public view_listener_t
}
else
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
// Estate owners and managers can always return objects.
if (region->canManageEstate())
{
new_value = true;
}
else
{
struct f : public LLSelectedObjectFunctor
{
virtual bool apply(LLViewerObject* obj)
{
return (obj->isOverAgentOwnedLand() ||
obj->isOverGroupOwnedLand() ||
obj->permModify());
}
} func;
const bool firstonly = true;
new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
}
}
new_value = can_derez(DRD_RETURN_TO_OWNER);
}
#endif
// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK
new_value &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn());
// [/RLVa:KB]
gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
return true;
}
@@ -4915,8 +4971,7 @@ void handle_take()
if(category_id.notNull())
{
// check trash
LLUUID trash;
trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash))
{
category_id.setNull();
@@ -4968,7 +5023,7 @@ void handle_take()
bool confirm_take(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotification::getSelectedOption(notification, response);
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if(enable_take() && (option == 0))
{
derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID());
@@ -5222,13 +5277,9 @@ BOOL sitting_on_selection()
}
// Need to determine if avatar is sitting on this object
LLVOAvatar* avatar = gAgentAvatarp;
if (!avatar)
{
return FALSE;
}
if (!isAgentAvatarValid()) return FALSE;
return (avatar->isSitting() && avatar->getRoot() == root_object);
return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object);
}
class LLToolsSaveToInventory : public view_listener_t
@@ -5958,16 +6009,16 @@ class LLWorldAlwaysRun : public view_listener_t
if (gAgent.getAlwaysRun())
{
gAgent.clearAlwaysRun();
gAgent.clearRunning();
// gAgent.clearRunning();
}
else
{
gAgent.setAlwaysRun();
gAgent.setRunning();
// gAgent.setRunning();
}
// tell the simulator.
gAgent.sendWalkRun(gAgent.getAlwaysRun());
// gAgent.sendWalkRun(gAgent.getAlwaysRun());
return true;
}
@@ -6136,6 +6187,10 @@ class LLToolsLookAtSelection : public view_listener_t
}
if (zoom)
{
// Make sure we are not increasing the distance between the camera and object
LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal();
distance = llmin(distance, (F32) orig_distance.length());
gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance),
LLSelectMgr::getInstance()->getSelectionCenterGlobal(),
object_id );
@@ -6757,13 +6812,6 @@ class LLShowAgentProfile : public view_listener_t
}
else if (userdata.asString() == "hit object")
{
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
{
return true;
}
// [/RLVa:KB]
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (objectp)
{
@@ -6776,7 +6824,10 @@ class LLShowAgentProfile : public view_listener_t
}
LLVOAvatar* avatar = find_avatar_from_object(agent_id);
if (avatar)
// if (avatar)
// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
if ( (avatar) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (gAgent.getID() == agent_id)) )
// [/RLVa:KB]
{
LLFloaterAvatarInfo::show( avatar->getID() );
}
@@ -6901,6 +6952,7 @@ void handle_move(void*)
class LLObjectAttachToAvatar : public view_listener_t
{
public:
LLObjectAttachToAvatar(bool replace) : mReplace(replace) {}
static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; }
private:
@@ -6927,27 +6979,43 @@ private:
}
// [/RLVa:KB]
confirm_replace_attachment(0, attachment_point);
confirmReplaceAttachment(0, attachment_point);
}
return true;
}
static void onNearAttachObject(BOOL success, void *user_data);
void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point);
struct CallbackData
{
CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {}
LLViewerJointAttachment* mAttachmentPoint;
bool mReplace;
};
protected:
static LLObjectSelectionHandle sObjectSelection;
bool mReplace;
};
LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection;
void near_attach_object(BOOL success, void *user_data)
// static
void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data)
{
if (!user_data) return;
CallbackData* cb_data = static_cast<CallbackData*>(user_data);
if (success)
{
LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;
const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint;
U8 attachment_id = 0;
if (attachment)
{
for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
{
if (iter->second == attachment)
@@ -6962,12 +7030,15 @@ void near_attach_object(BOOL success, void *user_data)
// interpret 0 as "default location"
attachment_id = 0;
}
LLSelectMgr::getInstance()->sendAttach(attachment_id);
LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace);
}
LLObjectAttachToAvatar::setObjectSelection(NULL);
delete cb_data;
}
void confirm_replace_attachment(S32 option, void* user_data)
// static
void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point)
{
if (option == 0/*YES*/)
{
@@ -6992,48 +7063,66 @@ void confirm_replace_attachment(S32 option, void* user_data)
delta = delta * 0.5f;
walkToSpot -= delta;
gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, near_attach_object, user_data, stop_distance);
// The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak.
CallbackData* user_data = new CallbackData(attachment_point, mReplace);
gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance);
gAgentCamera.clearFocusObject();
}
}
}
void callback_attachment_drop(const LLSD& notification, const LLSD& response)
{
// Ensure user confirmed the drop
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option != 0) return;
// Called when the user clicked on an object attached to them
// and selected "Drop".
LLUUID object_id = notification["payload"]["object_id"].asUUID();
LLViewerObject *object = gObjectList.findObject(object_id);
if (!object)
{
llwarns << "handle_drop_attachment() - no object to drop" << llendl;
return;
}
LLViewerObject *parent = (LLViewerObject*)object->getParent();
while (parent)
{
if(parent->isAvatar())
{
break;
}
object = parent;
parent = (LLViewerObject*)parent->getParent();
}
if (!object)
{
llwarns << "handle_detach() - no object to detach" << llendl;
return;
}
if (object->isAvatar())
{
llwarns << "Trying to detach avatar from avatar." << llendl;
return;
}
// reselect the object
LLSelectMgr::getInstance()->selectObjectAndFamily(object);
LLSelectMgr::getInstance()->sendDropAttachment();
return;
}
class LLAttachmentDrop : public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
// Called when the user clicked on an object attached to them
// and selected "Drop".
LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (!object)
{
llwarns << "handle_drop_attachment() - no object to drop" << llendl;
return true;
}
LLViewerObject *parent = (LLViewerObject*)object->getParent();
while (parent)
{
if(parent->isAvatar())
{
break;
}
object = parent;
parent = (LLViewerObject*)parent->getParent();
}
if (!object)
{
llwarns << "handle_detach() - no object to detach" << llendl;
return true;
}
if (object->isAvatar())
{
llwarns << "Trying to detach avatar from avatar." << llendl;
return true;
}
// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5 | OK
if (rlv_handler_t::isEnabled())
{
@@ -7052,11 +7141,20 @@ class LLAttachmentDrop : public view_listener_t
}
// [/RLVa:KB]
// The sendDropAttachment() method works on the list of selected
// objects. Thus we need to clear the list, make sure it only
// contains the object the user clicked, send the message,
// then clear the list.
LLSelectMgr::getInstance()->sendDropAttachment();
LLSD payload;
LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
if (object)
{
payload["object_id"] = object->getID();
}
else
{
llwarns << "Drop object not found" << llendl;
return true;
}
LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop);
return true;
}
};
@@ -7334,6 +7432,8 @@ BOOL object_selected_and_point_valid(void *user_data)
// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f | OK
if (rlv_handler_t::isEnabled())
{
if (!isAgentAvatarValid())
return FALSE;
// RELEASE-RLVa: look at the caller graph for this function on every new release
// -> 1.22.11 and 1.23.4
// - object_is_wearable() => dead code [user_data == NULL => default attach point => OK!]
@@ -9155,6 +9255,22 @@ class LLEditTakeOff : public view_listener_t
{
// MULTI-WEARABLES: assuming user wanted to remove top shirt.
U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearable(type)) )
{
// We'll use the first wearable we come across that can be removed (moving from top to bottom)
for (; wearable_index >= 0; wearable_index--)
{
const LLWearable* pWearable = gAgentWearables.getWearable(type, wearable_index);
if (!gRlvWearableLocks.isLockedWearable(pWearable))
break;
}
if (wearable_index < 0)
return true; // No wearable found that can be removed
}
// [/RLVa:KB]
LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index));
LLWearableBridge::removeItemFromAvatar(item);
}
@@ -9513,10 +9629,9 @@ void initialize_menus()
addMenu(new LLObjectTouch(), "Object.Touch");
addMenu(new LLObjectSitOrStand(), "Object.SitOrStand");
addMenu(new LLObjectDelete(), "Object.Delete");
addMenu(new LLObjectAttachToAvatar(), "Object.AttachToAvatar");
addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
addMenu(new LLObjectReturn(), "Object.Return");
addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
// <edit>
addMenu(new LLObjectMeasure(), "Object.Measure");
addMenu(new LLObjectData(), "Object.Data");