From 60d3dd98a44230c21803c1606552ee098ed9fa7c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 21 Feb 2024 21:05:14 +0100 Subject: Convert remaining BOOL to bool --- indra/newview/llgesturemgr.cpp | 114 ++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 57 deletions(-) (limited to 'indra/newview/llgesturemgr.cpp') diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index c0f773968d..20b3c94232 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -62,7 +62,7 @@ const F32 MAX_WAIT_ANIM_SECS = 30.f; // Lightweight constructor. // init() does the heavy lifting. LLGestureMgr::LLGestureMgr() -: mValid(FALSE), +: mValid(false), mPlaying(), mActive(), mLoadingCount(0) @@ -142,8 +142,8 @@ void LLGestureMgr::activateGesture(const LLUUID& item_id) mLoadingCount = 1; mDeactivateSimilarNames.clear(); - const BOOL inform_server = TRUE; - const BOOL deactivate_similar = FALSE; + const bool inform_server = true; + const bool deactivate_similar = false; activateGestureWithAsset(item_id, asset_id, inform_server, deactivate_similar); } @@ -182,8 +182,8 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) } // Don't inform server, we'll do that in bulk - const BOOL no_inform_server = FALSE; - const BOOL deactivate_similar = TRUE; + const bool no_inform_server = false; + const bool deactivate_similar = true; activateGestureWithAsset(item->getUUID(), item->getAssetUUID(), no_inform_server, deactivate_similar); @@ -192,7 +192,7 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) // Inform the database of this change LLMessageSystem* msg = gMessageSystem; - BOOL start_message = TRUE; + bool start_message = true; for (it = items.begin(); it != items.end(); ++it) { @@ -210,7 +210,7 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); msg->addU32("Flags", 0x0); - start_message = FALSE; + start_message = false; } msg->nextBlock("Data"); @@ -221,7 +221,7 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) if (msg->getCurrentSendTotal() > MTUBYTES) { gAgent.sendReliableMessage(); - start_message = TRUE; + start_message = true; } } @@ -235,8 +235,8 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) struct LLLoadInfo { LLUUID mItemID; - BOOL mInformServer; - BOOL mDeactivateSimilar; + bool mInformServer; + bool mDeactivateSimilar; }; // If inform_server is true, will send a message upstream to update @@ -246,8 +246,8 @@ struct LLLoadInfo */ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, const LLUUID& asset_id, - BOOL inform_server, - BOOL deactivate_similar) + bool inform_server, + bool deactivate_similar) { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); @@ -281,7 +281,7 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, info->mInformServer = inform_server; info->mDeactivateSimilar = deactivate_similar; - const BOOL high_priority = TRUE; + const bool high_priority = true; gAssetStorage->getAssetData(asset_id, LLAssetType::AT_GESTURE, onLoadComplete, @@ -388,7 +388,7 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i // Inform database of the change LLMessageSystem* msg = gMessageSystem; - BOOL start_message = TRUE; + bool start_message = true; uuid_vec_t::const_iterator vit = gest_item_ids.begin(); while (vit != gest_item_ids.end()) { @@ -399,7 +399,7 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); msg->addU32("Flags", 0x0); - start_message = FALSE; + start_message = false; } msg->nextBlock("Data"); @@ -409,7 +409,7 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i if (msg->getCurrentSendTotal() > MTUBYTES) { gAgent.sendReliableMessage(); - start_message = TRUE; + start_message = true; } ++vit; @@ -434,7 +434,7 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i } -BOOL LLGestureMgr::isGestureActive(const LLUUID& item_id) +bool LLGestureMgr::isGestureActive(const LLUUID& item_id) { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); item_map_t::iterator it = mActive.find(base_item_id); @@ -442,24 +442,24 @@ BOOL LLGestureMgr::isGestureActive(const LLUUID& item_id) } -BOOL LLGestureMgr::isGesturePlaying(const LLUUID& item_id) +bool LLGestureMgr::isGesturePlaying(const LLUUID& item_id) { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) return FALSE; + if (it == mActive.end()) return false; LLMultiGesture* gesture = (*it).second; - if (!gesture) return FALSE; + if (!gesture) return false; return gesture->mPlaying; } -BOOL LLGestureMgr::isGesturePlaying(LLMultiGesture* gesture) +bool LLGestureMgr::isGesturePlaying(LLMultiGesture* gesture) { if(!gesture) { - return FALSE; + return false; } return gesture->mPlaying; @@ -498,10 +498,10 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_ges LLLoadInfo* info = new LLLoadInfo; info->mItemID = base_item_id; - info->mInformServer = TRUE; - info->mDeactivateSimilar = FALSE; + info->mInformServer = true; + info->mDeactivateSimilar = false; - const BOOL high_priority = TRUE; + const bool high_priority = true; gAssetStorage->getAssetData(asset_id, LLAssetType::AT_GESTURE, onLoadComplete, @@ -536,7 +536,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) gesture->mCurrentStep = 0; // Add to list of playing - gesture->mPlaying = TRUE; + gesture->mPlaying = true; mPlaying.push_back(gesture); // Load all needed assets to minimize the delays @@ -565,7 +565,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) LLAssetType::AT_ANIMATION, onAssetLoadComplete, (void *)id, - TRUE); + true); } break; } @@ -582,7 +582,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) LLAssetType::AT_SOUND, onAssetLoadComplete, NULL, - TRUE); + true); } break; } @@ -624,12 +624,12 @@ void LLGestureMgr::playGesture(const LLUUID& item_id) // Iterates through space delimited tokens in string, triggering any gestures found. // Generates a revised string that has the found tokens replaced by their replacement strings // and (as a minor side effect) has multiple spaces in a row replaced by single spaces. -BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::string* revised_string) +bool LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::string* revised_string) { std::string tokenized = utf8str; - BOOL found_gestures = FALSE; - BOOL first_token = TRUE; + bool found_gestures = false; + bool first_token = true; typedef boost::tokenizer > tokenizer; boost::char_separator sep(" "); @@ -693,7 +693,7 @@ BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::strin revised_string->append( gesture->mReplaceText ); } } - found_gestures = TRUE; + found_gestures = true; } } } @@ -710,14 +710,14 @@ BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::strin revised_string->append( cur_token ); } - first_token = FALSE; + first_token = false; gesture = NULL; } return found_gestures; } -BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask) +bool LLGestureMgr::triggerGesture(KEY key, MASK mask) { std::vector matching; item_map_t::iterator it; @@ -745,9 +745,9 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask) LLMultiGesture* gesture = matching[random]; playGesture(gesture); - return TRUE; + return true; } - return FALSE; + return false; } @@ -860,7 +860,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) } // Run the current steps - BOOL waiting = FALSE; + bool waiting = false; while (!waiting && gesture->mPlaying) { // Get the current step, if there is one. @@ -874,7 +874,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) else { // step stays null, we're off the end - gesture->mWaitingAtEnd = TRUE; + gesture->mWaitingAtEnd = true; } @@ -889,12 +889,12 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) && gesture->mPlayingAnimIDs.empty())) { // all animations are done playing - gesture->mWaitingAtEnd = FALSE; - gesture->mPlaying = FALSE; + gesture->mWaitingAtEnd = false; + gesture->mPlaying = false; } else { - waiting = TRUE; + waiting = true; } continue; } @@ -909,7 +909,7 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) && gesture->mPlayingAnimIDs.empty())) { // all animations are done playing - gesture->mWaitingAnimations = FALSE; + gesture->mWaitingAnimations = false; gesture->mCurrentStep++; } else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS) @@ -917,12 +917,12 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) // we've waited too long for an animation LL_INFOS("GestureMgr") << "Waited too long for animations to stop, continuing gesture." << LL_ENDL; - gesture->mWaitingAnimations = FALSE; + gesture->mWaitingAnimations = false; gesture->mCurrentStep++; } else { - waiting = TRUE; + waiting = true; } continue; } @@ -938,13 +938,13 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) if (elapsed > wait_step->mWaitSeconds) { // wait is done, continue execution - gesture->mWaitingTimer = FALSE; + gesture->mWaitingTimer = false; gesture->mCurrentStep++; } else { // we're waiting, so execution is done for now - waiting = TRUE; + waiting = true; } continue; } @@ -1004,7 +1004,7 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) // Don't animate the nodding, as this might not blend with // other playing animations. - const BOOL animate = FALSE; + const bool animate = false; (LLFloaterReg::getTypedInstance("nearby_chat"))-> sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); @@ -1017,12 +1017,12 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) LLGestureStepWait* wait_step = (LLGestureStepWait*)step; if (wait_step->mFlags & WAIT_FLAG_TIME) { - gesture->mWaitingTimer = TRUE; + gesture->mWaitingTimer = true; gesture->mWaitTimer.reset(); } else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM) { - gesture->mWaitingAnimations = TRUE; + gesture->mWaitingAnimations = true; // Use the wait timer as a deadlock breaker for animation // waits. gesture->mWaitTimer.reset(); @@ -1050,8 +1050,8 @@ void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid, LLLoadInfo* info = (LLLoadInfo*)user_data; LLUUID item_id = info->mItemID; - BOOL inform_server = info->mInformServer; - BOOL deactivate_similar = info->mDeactivateSimilar; + bool inform_server = info->mInformServer; + bool deactivate_similar = info->mDeactivateSimilar; delete info; info = NULL; @@ -1072,7 +1072,7 @@ void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid, LLMultiGesture* gesture = new LLMultiGesture(); LLDataPackerAsciiBuffer dp(&buffer[0], size+1); - BOOL ok = gesture->deserialize(dp); + bool ok = gesture->deserialize(dp); if (ok) { @@ -1395,7 +1395,7 @@ void LLGestureMgr::notifyObservers() } } -BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) +bool LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) { S32 in_len = in_str.length(); @@ -1410,7 +1410,7 @@ BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) if (!LLStringUtil::compareInsensitive(in_str, trigger)) { *out_str = trigger; - return TRUE; + return true; } } } @@ -1461,7 +1461,7 @@ BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) } if (rest_of_match.compare("") == 0) { - return TRUE; + return true; } if (buf.compare("") != 0) { @@ -1475,10 +1475,10 @@ BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) if (rest_of_match.compare("") != 0) { *out_str = in_str+rest_of_match; - return TRUE; + return true; } - return FALSE; + return false; } -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/llgesturemgr.cpp | 3160 ++++++++++++++++++++-------------------- 1 file changed, 1580 insertions(+), 1580 deletions(-) (limited to 'indra/newview/llgesturemgr.cpp') diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index fcafd949c0..2ac99a2f16 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -1,1580 +1,1580 @@ -/** - * @file llgesturemgr.cpp - * @brief Manager for playing gestures on the viewer - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llgesturemgr.h" - -// system -#include -#include - -// library -#include "llaudioengine.h" -#include "lldatapacker.h" -#include "llfloaterreg.h" -#include "llinventory.h" -#include "llkeyframemotion.h" -#include "llmultigesture.h" -#include "llnotificationsutil.h" -#include "llstl.h" -#include "llstring.h" // todo: remove -#include "llfilesystem.h" -#include "message.h" - -// newview -#include "llagent.h" -#include "lldelayedgestureerror.h" -#include "llinventorymodel.h" -#include "llviewermessage.h" -#include "llvoavatarself.h" -#include "llviewerstats.h" -#include "llfloaterimnearbychat.h" -#include "llappearancemgr.h" -#include "llgesturelistener.h" - -// Longest time, in seconds, to wait for all animations to stop playing -const F32 MAX_WAIT_ANIM_SECS = 30.f; -// Longest time, in seconds, to wait for a key release. -// This should be relatively long, but not too long. 10 minutes is enough -const F32 MAX_WAIT_KEY_SECS = 60.f * 10.f; - -// Lightweight constructor. -// init() does the heavy lifting. -LLGestureMgr::LLGestureMgr() -: mValid(false), - mPlaying(), - mActive(), - mLoadingCount(0) -{ - gInventory.addObserver(this); - mListener.reset(new LLGestureListener()); -} - - -// We own the data for gestures, so clean them up. -LLGestureMgr::~LLGestureMgr() -{ - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - - delete gesture; - gesture = NULL; - } - gInventory.removeObserver(this); -} - - -void LLGestureMgr::init() -{ - // TODO -} - -void LLGestureMgr::changed(U32 mask) -{ - LLInventoryFetchItemsObserver::changed(mask); - - if (mask & LLInventoryObserver::GESTURE) - { - // If there was a gesture label changed, update all the names in the - // active gestures and then notify observers - if (mask & LLInventoryObserver::LABEL) - { - for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) - { - if(it->second) - { - LLViewerInventoryItem* item = gInventory.getItem(it->first); - if(item) - { - it->second->mName = item->getName(); - } - } - } - notifyObservers(); - } - // If there was a gesture added or removed notify observers - // STRUCTURE denotes that the inventory item has been moved - // In the case of deleting gesture, it is moved to the trash - else if(mask & LLInventoryObserver::ADD || - mask & LLInventoryObserver::REMOVE || - mask & LLInventoryObserver::STRUCTURE) - { - notifyObservers(); - } - } -} - - -// Use this version when you have the item_id but not the asset_id, -// and you KNOW the inventory is loaded. -void LLGestureMgr::activateGesture(const LLUUID& item_id) -{ - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (!item) return; - if (item->getType() != LLAssetType::AT_GESTURE) - return; - - LLUUID asset_id = item->getAssetUUID(); - - mLoadingCount = 1; - mDeactivateSimilarNames.clear(); - - const bool inform_server = true; - const bool deactivate_similar = false; - activateGestureWithAsset(item_id, asset_id, inform_server, deactivate_similar); -} - - -void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) -{ - // Load up the assets - S32 count = 0; - LLViewerInventoryItem::item_array_t::const_iterator it; - for (it = items.begin(); it != items.end(); ++it) - { - LLViewerInventoryItem* item = *it; - - if (isGestureActive(item->getUUID())) - { - continue; - } - else - { // Make gesture active and persistent through login sessions. -Aura 07-12-06 - activateGesture(item->getUUID()); - } - - count++; - } - - mLoadingCount = count; - mDeactivateSimilarNames.clear(); - - for (it = items.begin(); it != items.end(); ++it) - { - LLViewerInventoryItem* item = *it; - - if (isGestureActive(item->getUUID())) - { - continue; - } - - // Don't inform server, we'll do that in bulk - const bool no_inform_server = false; - const bool deactivate_similar = true; - activateGestureWithAsset(item->getUUID(), item->getAssetUUID(), - no_inform_server, - deactivate_similar); - } - - // Inform the database of this change - LLMessageSystem* msg = gMessageSystem; - - bool start_message = true; - - for (it = items.begin(); it != items.end(); ++it) - { - LLViewerInventoryItem* item = *it; - - if (isGestureActive(item->getUUID())) - { - continue; - } - - if (start_message) - { - msg->newMessage("ActivateGestures"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addU32("Flags", 0x0); - start_message = false; - } - - msg->nextBlock("Data"); - msg->addUUID("ItemID", item->getUUID()); - msg->addUUID("AssetID", item->getAssetUUID()); - msg->addU32("GestureFlags", 0x0); - - if (msg->getCurrentSendTotal() > MTUBYTES) - { - gAgent.sendReliableMessage(); - start_message = true; - } - } - - if (!start_message) - { - gAgent.sendReliableMessage(); - } -} - - -struct LLLoadInfo -{ - LLUUID mItemID; - bool mInformServer; - bool mDeactivateSimilar; -}; - -// If inform_server is true, will send a message upstream to update -// the user_gesture_active table. -/** - * It will load a gesture from remote storage - */ -void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, - const LLUUID& asset_id, - bool inform_server, - bool deactivate_similar) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - - if( !gAssetStorage ) - { - LL_WARNS() << "LLGestureMgr::activateGestureWithAsset without valid gAssetStorage" << LL_ENDL; - return; - } - // If gesture is already active, nothing to do. - if (isGestureActive(item_id)) - { - LL_WARNS() << "Tried to loadGesture twice " << item_id << LL_ENDL; - return; - } - -// if (asset_id.isNull()) -// { -// LL_WARNS() << "loadGesture() - gesture has no asset" << LL_ENDL; -// return; -// } - - // For now, put NULL into the item map. We'll build a gesture - // class object when the asset data arrives. - mActive[base_item_id] = NULL; - - // Copy the UUID - if (asset_id.notNull()) - { - LLLoadInfo* info = new LLLoadInfo; - info->mItemID = base_item_id; - info->mInformServer = inform_server; - info->mDeactivateSimilar = deactivate_similar; - - const bool high_priority = true; - gAssetStorage->getAssetData(asset_id, - LLAssetType::AT_GESTURE, - onLoadComplete, - (void*)info, - high_priority); - } - else - { - notifyObservers(); - } -} - - -void notify_update_label(const LLUUID& base_item_id) -{ - gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); - LLGestureMgr::instance().notifyObservers(); -} - -void LLGestureMgr::deactivateGesture(const LLUUID& item_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) - { - LL_WARNS() << "deactivateGesture for inactive gesture " << item_id << LL_ENDL; - return; - } - - // mActive owns this gesture pointer, so clean up memory. - LLMultiGesture* gesture = (*it).second; - - // Can be NULL gestures in the map - if (gesture) - { - stopGesture(gesture); - - delete gesture; - gesture = NULL; - } - - mActive.erase(it); - - // Inform the database of this change - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("DeactivateGestures"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addU32("Flags", 0x0); - - msg->nextBlock("Data"); - msg->addUUID("ItemID", item_id); - msg->addU32("GestureFlags", 0x0); - - gAgent.sendReliableMessage(); - - LLPointer cb = - new LLBoostFuncInventoryCallback(no_op_inventory_func, - boost::bind(notify_update_label,base_item_id)); - - LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb); -} - - -void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id) -{ - const LLUUID& base_in_item_id = gInventory.getLinkedItemID(in_item_id); - uuid_vec_t gest_item_ids; - - // Deactivate all gestures that match - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ) - { - const LLUUID& item_id = (*it).first; - LLMultiGesture* gest = (*it).second; - - // Don't deactivate the gesture we are looking for duplicates of - // (for replaceGesture) - if (!gest || item_id == base_in_item_id) - { - // legal, can have null pointers in list - ++it; - } - else if ((!gest->mTrigger.empty() && gest->mTrigger == in->mTrigger) - || (gest->mKey != KEY_NONE && gest->mKey == in->mKey && gest->mMask == in->mMask)) - { - gest_item_ids.push_back(item_id); - - stopGesture(gest); - - delete gest; - gest = NULL; - - mActive.erase(it++); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - - } - else - { - ++it; - } - } - - // Inform database of the change - LLMessageSystem* msg = gMessageSystem; - bool start_message = true; - uuid_vec_t::const_iterator vit = gest_item_ids.begin(); - while (vit != gest_item_ids.end()) - { - if (start_message) - { - msg->newMessage("DeactivateGestures"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addU32("Flags", 0x0); - start_message = false; - } - - msg->nextBlock("Data"); - msg->addUUID("ItemID", *vit); - msg->addU32("GestureFlags", 0x0); - - if (msg->getCurrentSendTotal() > MTUBYTES) - { - gAgent.sendReliableMessage(); - start_message = true; - } - - ++vit; - } - - if (!start_message) - { - gAgent.sendReliableMessage(); - } - - // Add to the list of names for the user. - for (vit = gest_item_ids.begin(); vit != gest_item_ids.end(); ++vit) - { - LLViewerInventoryItem* item = gInventory.getItem(*vit); - if (!item) continue; - - mDeactivateSimilarNames.append(item->getName()); - mDeactivateSimilarNames.append("\n"); - } - - notifyObservers(); -} - - -bool LLGestureMgr::isGestureActive(const LLUUID& item_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - item_map_t::iterator it = mActive.find(base_item_id); - return (it != mActive.end()); -} - - -bool LLGestureMgr::isGesturePlaying(const LLUUID& item_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - - item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) return false; - - LLMultiGesture* gesture = (*it).second; - if (!gesture) return false; - - return gesture->mPlaying; -} - -bool LLGestureMgr::isGesturePlaying(LLMultiGesture* gesture) -{ - if(!gesture) - { - return false; - } - - return gesture->mPlaying; -} - -void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - - item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) - { - LL_WARNS() << "replaceGesture for inactive gesture " << base_item_id << LL_ENDL; - return; - } - - LLMultiGesture* old_gesture = (*it).second; - stopGesture(old_gesture); - - mActive.erase(base_item_id); - - mActive[base_item_id] = new_gesture; - - // replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) - // replaces ids without repalcing gesture - if (old_gesture != new_gesture) - { - delete old_gesture; - old_gesture = NULL; - } - - if (asset_id.notNull()) - { - mLoadingCount = 1; - mDeactivateSimilarNames.clear(); - - LLLoadInfo* info = new LLLoadInfo; - info->mItemID = base_item_id; - info->mInformServer = true; - info->mDeactivateSimilar = false; - - const bool high_priority = true; - gAssetStorage->getAssetData(asset_id, - LLAssetType::AT_GESTURE, - onLoadComplete, - (void*)info, - high_priority); - } - - notifyObservers(); -} - -void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - - item_map_t::iterator it = LLGestureMgr::instance().mActive.find(base_item_id); - if (it == mActive.end()) - { - LL_WARNS() << "replaceGesture for inactive gesture " << base_item_id << LL_ENDL; - return; - } - - // mActive owns this gesture pointer, so clean up memory. - LLMultiGesture* gesture = (*it).second; - LLGestureMgr::instance().replaceGesture(base_item_id, gesture, new_asset_id); -} - -void LLGestureMgr::playGesture(LLMultiGesture* gesture, bool fromKeyPress) -{ - if (!gesture) return; - - // Reset gesture to first step - gesture->mCurrentStep = 0; - gesture->mTriggeredByKey = fromKeyPress; - - // Add to list of playing - gesture->mPlaying = true; - mPlaying.push_back(gesture); - - // Load all needed assets to minimize the delays - // when gesture is playing. - for (std::vector::iterator steps_it = gesture->mSteps.begin(); - steps_it != gesture->mSteps.end(); - ++steps_it) - { - LLGestureStep* step = *steps_it; - switch(step->getType()) - { - case STEP_ANIMATION: - { - LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; - const LLUUID& anim_id = anim_step->mAnimAssetID; - - // Don't request the animation if this step stops it or if it is already in the cache - if (!(anim_id.isNull() - || anim_step->mFlags & ANIM_FLAG_STOP - || gAssetStorage->hasLocalAsset(anim_id, LLAssetType::AT_ANIMATION))) - { - mLoadingAssets.insert(anim_id); - - LLUUID* id = new LLUUID(gAgentID); - gAssetStorage->getAssetData(anim_id, - LLAssetType::AT_ANIMATION, - onAssetLoadComplete, - (void *)id, - true); - } - break; - } - case STEP_SOUND: - { - LLGestureStepSound* sound_step = (LLGestureStepSound*)step; - const LLUUID& sound_id = sound_step->mSoundAssetID; - if (!(sound_id.isNull() - || gAssetStorage->hasLocalAsset(sound_id, LLAssetType::AT_SOUND))) - { - mLoadingAssets.insert(sound_id); - - gAssetStorage->getAssetData(sound_id, - LLAssetType::AT_SOUND, - onAssetLoadComplete, - NULL, - true); - } - break; - } - case STEP_CHAT: - case STEP_WAIT: - case STEP_EOF: - { - break; - } - default: - { - LL_WARNS() << "Unknown gesture step type: " << step->getType() << LL_ENDL; - } - } - } - - // And get it going - stepGesture(gesture); - - notifyObservers(); -} - - -// Convenience function that looks up the item_id for you. -void LLGestureMgr::playGesture(const LLUUID& item_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - - item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) return; - - LLMultiGesture* gesture = (*it).second; - if (!gesture) return; - - playGesture(gesture); -} - - -// Iterates through space delimited tokens in string, triggering any gestures found. -// Generates a revised string that has the found tokens replaced by their replacement strings -// and (as a minor side effect) has multiple spaces in a row replaced by single spaces. -bool LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::string* revised_string) -{ - std::string tokenized = utf8str; - - bool found_gestures = false; - bool first_token = true; - - typedef boost::tokenizer > tokenizer; - boost::char_separator sep(" "); - tokenizer tokens(tokenized, sep); - tokenizer::iterator token_iter; - - for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - const char* cur_token = token_iter->c_str(); - LLMultiGesture* gesture = NULL; - - // Only pay attention to the first gesture in the string. - if( !found_gestures ) - { - // collect gestures that match - std::vector matching; - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ++it) - { - gesture = (*it).second; - - // Gesture asset data might not have arrived yet - if (!gesture) continue; - - if (LLStringUtil::compareInsensitive(gesture->mTrigger, cur_token) == 0) - { - matching.push_back(gesture); - } - - gesture = NULL; - } - - - if (matching.size() > 0) - { - // choose one at random - { - S32 random = ll_rand(matching.size()); - - gesture = matching[random]; - - playGesture(gesture); - - if (!gesture->mReplaceText.empty()) - { - if( !first_token ) - { - if (revised_string) - revised_string->append( " " ); - } - - // Don't muck with the user's capitalization if we don't have to. - if( LLStringUtil::compareInsensitive(cur_token, gesture->mReplaceText) == 0) - { - if (revised_string) - revised_string->append( cur_token ); - } - else - { - if (revised_string) - revised_string->append( gesture->mReplaceText ); - } - } - found_gestures = true; - } - } - } - - if(!gesture) - { - // This token doesn't match a gesture. Pass it through to the output. - if( !first_token ) - { - if (revised_string) - revised_string->append( " " ); - } - if (revised_string) - revised_string->append( cur_token ); - } - - first_token = false; - gesture = NULL; - } - return found_gestures; -} - - -bool LLGestureMgr::triggerGesture(KEY key, MASK mask) -{ - std::vector matching; - item_map_t::iterator it; - - // collect matching gestures - for (it = mActive.begin(); it != mActive.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - - // asset data might not have arrived yet - if (!gesture) continue; - - if (gesture->mKey == key - && gesture->mMask == mask - && gesture->mWaitingKeyRelease == false) - { - matching.push_back(gesture); - } - } - - // choose one and play it - if (matching.size() > 0) - { - U32 random = ll_rand(matching.size()); - - LLMultiGesture* gesture = matching[random]; - - playGesture(gesture, true); - return true; - } - return false; -} - - -bool LLGestureMgr::triggerGestureRelease(KEY key, MASK mask) -{ - std::vector matching; - item_map_t::iterator it; - - // collect matching gestures - for (it = mActive.begin(); it != mActive.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - - // asset data might not have arrived yet - if (!gesture) continue; - - if (gesture->mKey == key - && gesture->mMask == mask) - { - gesture->mKeyReleased = true; - } - } - - //If we found one, block. Otherwise tell them it's free to go. - return matching.size() > 0; -} - - -S32 LLGestureMgr::getPlayingCount() const -{ - return mPlaying.size(); -} - - -struct IsGesturePlaying -{ - bool operator()(const LLMultiGesture* gesture) const - { - return bool(gesture->mPlaying); - } -}; - -void LLGestureMgr::update() -{ - S32 i; - for (i = 0; i < (S32)mPlaying.size(); ++i) - { - stepGesture(mPlaying[i]); - } - - // Clear out gestures that are done, by moving all the - // ones that are still playing to the front. - std::vector::iterator new_end; - new_end = std::partition(mPlaying.begin(), - mPlaying.end(), - IsGesturePlaying()); - - // Something finished playing - if (new_end != mPlaying.end()) - { - // Delete the completed gestures that want deletion - std::vector::iterator it; - for (it = new_end; it != mPlaying.end(); ++it) - { - LLMultiGesture* gesture = *it; - - if (gesture->mDoneCallback) - { - gesture->mDoneCallback(gesture, gesture->mCallbackData); - - // callback might have deleted gesture, can't - // rely on this pointer any more - gesture = NULL; - } - } - - // And take done gestures out of the playing list - mPlaying.erase(new_end, mPlaying.end()); - - notifyObservers(); - } -} - - -// Run all steps until you're either done or hit a wait. -void LLGestureMgr::stepGesture(LLMultiGesture* gesture) -{ - if (!gesture) - { - return; - } - if (!isAgentAvatarValid() || hasLoadingAssets(gesture)) return; - - // Of the ones that started playing, have any stopped? - - std::set::iterator gest_it; - for (gest_it = gesture->mPlayingAnimIDs.begin(); - gest_it != gesture->mPlayingAnimIDs.end(); - ) - { - // look in signaled animations (simulator's view of what is - // currently playing. - LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); - if (play_it != gAgentAvatarp->mSignaledAnimations.end()) - { - ++gest_it; - } - else - { - // not found, so not currently playing or scheduled to play - // delete from the triggered set - gesture->mPlayingAnimIDs.erase(gest_it++); - } - } - - // Of all the animations that we asked the sim to start for us, - // pick up the ones that have actually started. - for (gest_it = gesture->mRequestedAnimIDs.begin(); - gest_it != gesture->mRequestedAnimIDs.end(); - ) - { - LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); - if (play_it != gAgentAvatarp->mSignaledAnimations.end()) - { - // Hooray, this animation has started playing! - // Copy into playing. - gesture->mPlayingAnimIDs.insert(*gest_it); - gesture->mRequestedAnimIDs.erase(gest_it++); - } - else - { - // nope, not playing yet - ++gest_it; - } - } - - // Run the current steps - bool waiting = false; - while (!waiting && gesture->mPlaying) - { - // Get the current step, if there is one. - // Otherwise enter the waiting at end state. - LLGestureStep* step = NULL; - if (gesture->mCurrentStep < (S32)gesture->mSteps.size()) - { - step = gesture->mSteps[gesture->mCurrentStep]; - llassert(step != NULL); - } - else - { - // step stays null, we're off the end - gesture->mWaitingAtEnd = true; - } - - - // If we're waiting at the end, wait for all gestures to stop - // playing. - // TODO: Wait for all sounds to complete as well. - if (gesture->mWaitingAtEnd) - { - // Neither do we have any pending requests, nor are they - // still playing. - if ((gesture->mRequestedAnimIDs.empty() - && gesture->mPlayingAnimIDs.empty())) - { - // all animations are done playing - gesture->mWaitingAtEnd = false; - gesture->mPlaying = false; - } - else - { - waiting = true; - } - continue; - } - - // If we're waiting a fixed amount of time, check for timer - // expiration. - if (gesture->mWaitingKeyRelease) - { - // We're waiting for a certain amount of time to pass - if (gesture->mKeyReleased) - { - // wait is done, continue execution - gesture->mWaitingKeyRelease = false; - gesture->mCurrentStep++; - } - else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_KEY_SECS) - { - LL_INFOS("GestureMgr") << "Waited too long for key release, continuing gesture." - << LL_ENDL; - gesture->mWaitingKeyRelease = false; - gesture->mCurrentStep++; - } - else - { - // we're waiting, so execution is done for now - waiting = true; - } - continue; - } - - // If we're waiting on our animations to stop, poll for - // completion. - if (gesture->mWaitingAnimations) - { - // Neither do we have any pending requests, nor are they - // still playing. - if ((gesture->mRequestedAnimIDs.empty() - && gesture->mPlayingAnimIDs.empty())) - { - // all animations are done playing - gesture->mWaitingAnimations = false; - gesture->mCurrentStep++; - } - else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS) - { - // we've waited too long for an animation - LL_INFOS("GestureMgr") << "Waited too long for animations to stop, continuing gesture." - << LL_ENDL; - gesture->mWaitingAnimations = false; - gesture->mCurrentStep++; - } - else - { - waiting = true; - } - continue; - } - - // If we're waiting a fixed amount of time, check for timer - // expiration. - if (gesture->mWaitingTimer) - { - // We're waiting for a certain amount of time to pass - LLGestureStepWait* wait_step = (LLGestureStepWait*)step; - - F32 elapsed = gesture->mWaitTimer.getElapsedTimeF32(); - if (elapsed > wait_step->mWaitSeconds) - { - // wait is done, continue execution - gesture->mWaitingTimer = false; - gesture->mCurrentStep++; - } - else - { - // we're waiting, so execution is done for now - waiting = true; - } - continue; - } - - // Not waiting, do normal execution - runStep(gesture, step); - } -} - - -void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) -{ - switch(step->getType()) - { - case STEP_ANIMATION: - { - LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; - if (anim_step->mAnimAssetID.isNull()) - { - gesture->mCurrentStep++; - } - - if (anim_step->mFlags & ANIM_FLAG_STOP) - { - gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_STOP); - // remove it from our request set in case we just requested it - std::set::iterator set_it = gesture->mRequestedAnimIDs.find(anim_step->mAnimAssetID); - if (set_it != gesture->mRequestedAnimIDs.end()) - { - gesture->mRequestedAnimIDs.erase(set_it); - } - } - else - { - gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_START); - // Indicate that we've requested this animation to play as - // part of this gesture (but it won't start playing for at - // least one round-trip to simulator). - gesture->mRequestedAnimIDs.insert(anim_step->mAnimAssetID); - } - gesture->mCurrentStep++; - break; - } - case STEP_SOUND: - { - LLGestureStepSound* sound_step = (LLGestureStepSound*)step; - const LLUUID& sound_id = sound_step->mSoundAssetID; - const F32 volume = 1.f; - send_sound_trigger(sound_id, volume); - gesture->mCurrentStep++; - break; - } - case STEP_CHAT: - { - LLGestureStepChat* chat_step = (LLGestureStepChat*)step; - std::string chat_text = chat_step->mChatText; - // Don't animate the nodding, as this might not blend with - // other playing animations. - - const bool animate = false; - - (LLFloaterReg::getTypedInstance("nearby_chat"))-> - sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); - - gesture->mCurrentStep++; - break; - } - case STEP_WAIT: - { - LLGestureStepWait* wait_step = (LLGestureStepWait*)step; - if (gesture->mTriggeredByKey // Only wait here IF we were triggered by a key! - && gesture->mWaitingKeyRelease == false // We can only do this once! Prevent gestures infinitely running - && wait_step->mFlags & WAIT_FLAG_KEY_RELEASE) - { - // Lets wait for the key release first so we don't hold up re-presses - gesture->mWaitingKeyRelease = true; - gesture->mKeyReleased = false; - // Use the wait timer as a deadlock breaker for key release waits. - gesture->mWaitTimer.reset(); - } - else if (wait_step->mFlags & WAIT_FLAG_TIME) - { - gesture->mWaitingTimer = true; - gesture->mWaitTimer.reset(); - } - else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM) - { - gesture->mWaitingAnimations = true; - // Use the wait timer as a deadlock breaker for animation waits. - gesture->mWaitTimer.reset(); - } - else - { - gesture->mCurrentStep++; - } - // Don't increment instruction pointer until wait is complete. - break; - } - default: - { - break; - } - } -} - - -// static -void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) -{ - LLLoadInfo* info = (LLLoadInfo*)user_data; - - LLUUID item_id = info->mItemID; - bool inform_server = info->mInformServer; - bool deactivate_similar = info->mDeactivateSimilar; - - delete info; - info = NULL; - LLGestureMgr& self = LLGestureMgr::instance(); - self.mLoadingCount--; - - if (0 == status) - { - LLFileSystem file(asset_uuid, type, LLFileSystem::READ); - S32 size = file.getSize(); - - std::vector buffer(size+1); - - file.read((U8*)&buffer[0], size); - // ensure there's a trailing NULL so strlen will work. - buffer[size] = '\0'; - - LLMultiGesture* gesture = new LLMultiGesture(); - - LLDataPackerAsciiBuffer dp(&buffer[0], size+1); - bool ok = gesture->deserialize(dp); - - if (ok) - { - if (deactivate_similar) - { - self.deactivateSimilarGestures(gesture, item_id); - - // Display deactivation message if this was the last of the bunch. - if (self.mLoadingCount == 0 - && self.mDeactivateSimilarNames.length() > 0) - { - // we're done with this set of deactivations - LLSD args; - args["NAMES"] = self.mDeactivateSimilarNames; - LLNotificationsUtil::add("DeactivatedGesturesTrigger", args); - } - } - - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if(item) - { - gesture->mName = item->getName(); - } - else - { - // Watch this item and set gesture name when item exists in inventory - self.setFetchID(item_id); - self.startFetch(); - } - - item_map_t::iterator it = self.mActive.find(item_id); - if (it == self.mActive.end()) - { - // Gesture is supposed to be present, active, but NULL - LL_DEBUGS("GestureMgr") << "Gesture " << item_id << " not found in active list" << LL_ENDL; - } - else - { - LLMultiGesture* old_gesture = (*it).second; - if (old_gesture && old_gesture != gesture) - { - LL_DEBUGS("GestureMgr") << "Received dupplicate " << item_id << " callback" << LL_ENDL; - // In case somebody managest to activate, deactivate and - // then activate gesture again, before asset finishes loading. - // LLLoadInfo will have a different pointer, asset storage will - // see it as a different request, resulting in two callbacks. - - // deactivateSimilarGestures() did not turn this one off - // because of matching item_id - self.stopGesture(old_gesture); - - self.mActive.erase(item_id); - delete old_gesture; - old_gesture = NULL; - } - } - - self.mActive[item_id] = gesture; - - // Everything has been successful. Add to the active list. - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - - if (inform_server) - { - // Inform the database of this change - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("ActivateGestures"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addU32("Flags", 0x0); - - msg->nextBlock("Data"); - msg->addUUID("ItemID", item_id); - msg->addUUID("AssetID", asset_uuid); - msg->addU32("GestureFlags", 0x0); - - gAgent.sendReliableMessage(); - } - callback_map_t::iterator i_cb = self.mCallbackMap.find(item_id); - - if(i_cb != self.mCallbackMap.end()) - { - i_cb->second(gesture); - self.mCallbackMap.erase(i_cb); - } - - self.notifyObservers(); - } - else - { - LL_WARNS("GestureMgr") << "Unable to load gesture" << LL_ENDL; - - item_map_t::iterator it = self.mActive.find(item_id); - if (it != self.mActive.end()) - { - LLMultiGesture* old_gesture = (*it).second; - if (old_gesture) - { - // Shouldn't happen, just in case - LL_WARNS("GestureMgr") << "Gesture " << item_id << " existed when it shouldn't" << LL_ENDL; - - self.stopGesture(old_gesture); - delete old_gesture; - old_gesture = NULL; - } - self.mActive.erase(item_id); - } - - delete gesture; - gesture = NULL; - } - } - else - { - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || - LL_ERR_FILE_EMPTY == status) - { - LLDelayedGestureError::gestureMissing( item_id ); - } - else - { - LLDelayedGestureError::gestureFailedToLoad( item_id ); - } - - LL_WARNS("GestureMgr") << "Problem loading gesture: " << status << LL_ENDL; - - item_map_t::iterator it = self.mActive.find(item_id); - if (it != self.mActive.end()) - { - LLMultiGesture* old_gesture = (*it).second; - if (old_gesture) - { - // Shouldn't happen, just in case - LL_WARNS("GestureMgr") << "Gesture " << item_id << " existed when it shouldn't" << LL_ENDL; - - self.stopGesture(old_gesture); - delete old_gesture; - old_gesture = NULL; - } - self.mActive.erase(item_id); - } - } -} - -// static -void LLGestureMgr::onAssetLoadComplete(const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) -{ - LLGestureMgr& self = LLGestureMgr::instance(); - - // Complete the asset loading process depending on the type and - // remove the asset id from pending downloads list. - switch(type) - { - case LLAssetType::AT_ANIMATION: - { - LLKeyframeMotion::onLoadComplete(asset_uuid, type, user_data, status, ext_status); - - self.mLoadingAssets.erase(asset_uuid); - - break; - } - case LLAssetType::AT_SOUND: - { - LLAudioEngine::assetCallback(asset_uuid, type, user_data, status, ext_status); - - self.mLoadingAssets.erase(asset_uuid); - - break; - } - default: - { - LL_WARNS() << "Unexpected asset type: " << type << LL_ENDL; - - // We don't want to return from this callback without - // an animation or sound callback being fired - // and *user_data handled to avoid memory leaks. - llassert(type == LLAssetType::AT_ANIMATION || type == LLAssetType::AT_SOUND); - } - } -} - -// static -bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture) -{ - LLGestureMgr& self = LLGestureMgr::instance(); - - for (std::vector::iterator steps_it = gesture->mSteps.begin(); - steps_it != gesture->mSteps.end(); - ++steps_it) - { - LLGestureStep* step = *steps_it; - switch(step->getType()) - { - case STEP_ANIMATION: - { - LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; - const LLUUID& anim_id = anim_step->mAnimAssetID; - - if (!(anim_id.isNull() - || anim_step->mFlags & ANIM_FLAG_STOP - || self.mLoadingAssets.find(anim_id) == self.mLoadingAssets.end())) - { - return true; - } - break; - } - case STEP_SOUND: - { - LLGestureStepSound* sound_step = (LLGestureStepSound*)step; - const LLUUID& sound_id = sound_step->mSoundAssetID; - - if (!(sound_id.isNull() - || self.mLoadingAssets.find(sound_id) == self.mLoadingAssets.end())) - { - return true; - } - break; - } - case STEP_CHAT: - case STEP_WAIT: - case STEP_EOF: - { - break; - } - default: - { - LL_WARNS() << "Unknown gesture step type: " << step->getType() << LL_ENDL; - } - } - } - - return false; -} - -void LLGestureMgr::stopGesture(LLMultiGesture* gesture) -{ - if (!gesture) return; - - // Stop any animations that this gesture is currently playing - std::set::const_iterator set_it; - for (set_it = gesture->mRequestedAnimIDs.begin(); set_it != gesture->mRequestedAnimIDs.end(); ++set_it) - { - const LLUUID& anim_id = *set_it; - gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); - } - for (set_it = gesture->mPlayingAnimIDs.begin(); set_it != gesture->mPlayingAnimIDs.end(); ++set_it) - { - const LLUUID& anim_id = *set_it; - gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); - } - - std::vector::iterator it; - it = std::find(mPlaying.begin(), mPlaying.end(), gesture); - while (it != mPlaying.end()) - { - mPlaying.erase(it); - it = std::find(mPlaying.begin(), mPlaying.end(), gesture); - } - - gesture->reset(); - - if (gesture->mDoneCallback) - { - gesture->mDoneCallback(gesture, gesture->mCallbackData); - - // callback might have deleted gesture, can't - // rely on this pointer any more - gesture = NULL; - } - - notifyObservers(); -} - - -void LLGestureMgr::stopGesture(const LLUUID& item_id) -{ - const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - - item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) return; - - LLMultiGesture* gesture = (*it).second; - if (!gesture) return; - - stopGesture(gesture); -} - - -void LLGestureMgr::addObserver(LLGestureManagerObserver* observer) -{ - mObservers.push_back(observer); -} - -void LLGestureMgr::removeObserver(LLGestureManagerObserver* observer) -{ - std::vector::iterator it; - it = std::find(mObservers.begin(), mObservers.end(), observer); - if (it != mObservers.end()) - { - mObservers.erase(it); - } -} - -// Call this method when it's time to update everyone on a new state. -// Copy the list because an observer could respond by removing itself -// from the list. -void LLGestureMgr::notifyObservers() -{ - LL_DEBUGS() << "LLGestureMgr::notifyObservers" << LL_ENDL; - - for(std::vector::iterator iter = mObservers.begin(); - iter != mObservers.end(); - ++iter) - { - LLGestureManagerObserver* observer = (*iter); - observer->changed(); - } -} - -bool LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) -{ - S32 in_len = in_str.length(); - - //return whole trigger, if received text equals to it - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - if (gesture) - { - const std::string& trigger = gesture->getTrigger(); - if (!LLStringUtil::compareInsensitive(in_str, trigger)) - { - *out_str = trigger; - return true; - } - } - } - - //return common chars, if more than one trigger matches the prefix - std::string rest_of_match = ""; - std::string buf = ""; - for (it = mActive.begin(); it != mActive.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - if (gesture) - { - const std::string& trigger = gesture->getTrigger(); - - if (in_len > (S32)trigger.length()) - { - // too short, bail out - continue; - } - - std::string trigger_trunc = trigger; - LLStringUtil::truncate(trigger_trunc, in_len); - if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc)) - { - if (rest_of_match.compare("") == 0) - { - rest_of_match = trigger.substr(in_str.size()); - } - std::string cur_rest_of_match = trigger.substr(in_str.size()); - buf = ""; - S32 i=0; - - while (ipush_back(it->first); - } -} - -void LLGestureMgr::done() -{ - bool notify = false; - for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) - { - if(it->second && it->second->mName.empty()) - { - LLViewerInventoryItem* item = gInventory.getItem(it->first); - if(item) - { - it->second->mName = item->getName(); - notify = true; - } - } - } - if(notify) - { - notifyObservers(); - } -} - - +/** + * @file llgesturemgr.cpp + * @brief Manager for playing gestures on the viewer + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llgesturemgr.h" + +// system +#include +#include + +// library +#include "llaudioengine.h" +#include "lldatapacker.h" +#include "llfloaterreg.h" +#include "llinventory.h" +#include "llkeyframemotion.h" +#include "llmultigesture.h" +#include "llnotificationsutil.h" +#include "llstl.h" +#include "llstring.h" // todo: remove +#include "llfilesystem.h" +#include "message.h" + +// newview +#include "llagent.h" +#include "lldelayedgestureerror.h" +#include "llinventorymodel.h" +#include "llviewermessage.h" +#include "llvoavatarself.h" +#include "llviewerstats.h" +#include "llfloaterimnearbychat.h" +#include "llappearancemgr.h" +#include "llgesturelistener.h" + +// Longest time, in seconds, to wait for all animations to stop playing +const F32 MAX_WAIT_ANIM_SECS = 30.f; +// Longest time, in seconds, to wait for a key release. +// This should be relatively long, but not too long. 10 minutes is enough +const F32 MAX_WAIT_KEY_SECS = 60.f * 10.f; + +// Lightweight constructor. +// init() does the heavy lifting. +LLGestureMgr::LLGestureMgr() +: mValid(false), + mPlaying(), + mActive(), + mLoadingCount(0) +{ + gInventory.addObserver(this); + mListener.reset(new LLGestureListener()); +} + + +// We own the data for gestures, so clean them up. +LLGestureMgr::~LLGestureMgr() +{ + item_map_t::iterator it; + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + + delete gesture; + gesture = NULL; + } + gInventory.removeObserver(this); +} + + +void LLGestureMgr::init() +{ + // TODO +} + +void LLGestureMgr::changed(U32 mask) +{ + LLInventoryFetchItemsObserver::changed(mask); + + if (mask & LLInventoryObserver::GESTURE) + { + // If there was a gesture label changed, update all the names in the + // active gestures and then notify observers + if (mask & LLInventoryObserver::LABEL) + { + for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) + { + if(it->second) + { + LLViewerInventoryItem* item = gInventory.getItem(it->first); + if(item) + { + it->second->mName = item->getName(); + } + } + } + notifyObservers(); + } + // If there was a gesture added or removed notify observers + // STRUCTURE denotes that the inventory item has been moved + // In the case of deleting gesture, it is moved to the trash + else if(mask & LLInventoryObserver::ADD || + mask & LLInventoryObserver::REMOVE || + mask & LLInventoryObserver::STRUCTURE) + { + notifyObservers(); + } + } +} + + +// Use this version when you have the item_id but not the asset_id, +// and you KNOW the inventory is loaded. +void LLGestureMgr::activateGesture(const LLUUID& item_id) +{ + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (!item) return; + if (item->getType() != LLAssetType::AT_GESTURE) + return; + + LLUUID asset_id = item->getAssetUUID(); + + mLoadingCount = 1; + mDeactivateSimilarNames.clear(); + + const bool inform_server = true; + const bool deactivate_similar = false; + activateGestureWithAsset(item_id, asset_id, inform_server, deactivate_similar); +} + + +void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) +{ + // Load up the assets + S32 count = 0; + LLViewerInventoryItem::item_array_t::const_iterator it; + for (it = items.begin(); it != items.end(); ++it) + { + LLViewerInventoryItem* item = *it; + + if (isGestureActive(item->getUUID())) + { + continue; + } + else + { // Make gesture active and persistent through login sessions. -Aura 07-12-06 + activateGesture(item->getUUID()); + } + + count++; + } + + mLoadingCount = count; + mDeactivateSimilarNames.clear(); + + for (it = items.begin(); it != items.end(); ++it) + { + LLViewerInventoryItem* item = *it; + + if (isGestureActive(item->getUUID())) + { + continue; + } + + // Don't inform server, we'll do that in bulk + const bool no_inform_server = false; + const bool deactivate_similar = true; + activateGestureWithAsset(item->getUUID(), item->getAssetUUID(), + no_inform_server, + deactivate_similar); + } + + // Inform the database of this change + LLMessageSystem* msg = gMessageSystem; + + bool start_message = true; + + for (it = items.begin(); it != items.end(); ++it) + { + LLViewerInventoryItem* item = *it; + + if (isGestureActive(item->getUUID())) + { + continue; + } + + if (start_message) + { + msg->newMessage("ActivateGestures"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addU32("Flags", 0x0); + start_message = false; + } + + msg->nextBlock("Data"); + msg->addUUID("ItemID", item->getUUID()); + msg->addUUID("AssetID", item->getAssetUUID()); + msg->addU32("GestureFlags", 0x0); + + if (msg->getCurrentSendTotal() > MTUBYTES) + { + gAgent.sendReliableMessage(); + start_message = true; + } + } + + if (!start_message) + { + gAgent.sendReliableMessage(); + } +} + + +struct LLLoadInfo +{ + LLUUID mItemID; + bool mInformServer; + bool mDeactivateSimilar; +}; + +// If inform_server is true, will send a message upstream to update +// the user_gesture_active table. +/** + * It will load a gesture from remote storage + */ +void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, + const LLUUID& asset_id, + bool inform_server, + bool deactivate_similar) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + + if( !gAssetStorage ) + { + LL_WARNS() << "LLGestureMgr::activateGestureWithAsset without valid gAssetStorage" << LL_ENDL; + return; + } + // If gesture is already active, nothing to do. + if (isGestureActive(item_id)) + { + LL_WARNS() << "Tried to loadGesture twice " << item_id << LL_ENDL; + return; + } + +// if (asset_id.isNull()) +// { +// LL_WARNS() << "loadGesture() - gesture has no asset" << LL_ENDL; +// return; +// } + + // For now, put NULL into the item map. We'll build a gesture + // class object when the asset data arrives. + mActive[base_item_id] = NULL; + + // Copy the UUID + if (asset_id.notNull()) + { + LLLoadInfo* info = new LLLoadInfo; + info->mItemID = base_item_id; + info->mInformServer = inform_server; + info->mDeactivateSimilar = deactivate_similar; + + const bool high_priority = true; + gAssetStorage->getAssetData(asset_id, + LLAssetType::AT_GESTURE, + onLoadComplete, + (void*)info, + high_priority); + } + else + { + notifyObservers(); + } +} + + +void notify_update_label(const LLUUID& base_item_id) +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id); + LLGestureMgr::instance().notifyObservers(); +} + +void LLGestureMgr::deactivateGesture(const LLUUID& item_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + item_map_t::iterator it = mActive.find(base_item_id); + if (it == mActive.end()) + { + LL_WARNS() << "deactivateGesture for inactive gesture " << item_id << LL_ENDL; + return; + } + + // mActive owns this gesture pointer, so clean up memory. + LLMultiGesture* gesture = (*it).second; + + // Can be NULL gestures in the map + if (gesture) + { + stopGesture(gesture); + + delete gesture; + gesture = NULL; + } + + mActive.erase(it); + + // Inform the database of this change + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("DeactivateGestures"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addU32("Flags", 0x0); + + msg->nextBlock("Data"); + msg->addUUID("ItemID", item_id); + msg->addU32("GestureFlags", 0x0); + + gAgent.sendReliableMessage(); + + LLPointer cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(notify_update_label,base_item_id)); + + LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb); +} + + +void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id) +{ + const LLUUID& base_in_item_id = gInventory.getLinkedItemID(in_item_id); + uuid_vec_t gest_item_ids; + + // Deactivate all gestures that match + item_map_t::iterator it; + for (it = mActive.begin(); it != mActive.end(); ) + { + const LLUUID& item_id = (*it).first; + LLMultiGesture* gest = (*it).second; + + // Don't deactivate the gesture we are looking for duplicates of + // (for replaceGesture) + if (!gest || item_id == base_in_item_id) + { + // legal, can have null pointers in list + ++it; + } + else if ((!gest->mTrigger.empty() && gest->mTrigger == in->mTrigger) + || (gest->mKey != KEY_NONE && gest->mKey == in->mKey && gest->mMask == in->mMask)) + { + gest_item_ids.push_back(item_id); + + stopGesture(gest); + + delete gest; + gest = NULL; + + mActive.erase(it++); + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + + } + else + { + ++it; + } + } + + // Inform database of the change + LLMessageSystem* msg = gMessageSystem; + bool start_message = true; + uuid_vec_t::const_iterator vit = gest_item_ids.begin(); + while (vit != gest_item_ids.end()) + { + if (start_message) + { + msg->newMessage("DeactivateGestures"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addU32("Flags", 0x0); + start_message = false; + } + + msg->nextBlock("Data"); + msg->addUUID("ItemID", *vit); + msg->addU32("GestureFlags", 0x0); + + if (msg->getCurrentSendTotal() > MTUBYTES) + { + gAgent.sendReliableMessage(); + start_message = true; + } + + ++vit; + } + + if (!start_message) + { + gAgent.sendReliableMessage(); + } + + // Add to the list of names for the user. + for (vit = gest_item_ids.begin(); vit != gest_item_ids.end(); ++vit) + { + LLViewerInventoryItem* item = gInventory.getItem(*vit); + if (!item) continue; + + mDeactivateSimilarNames.append(item->getName()); + mDeactivateSimilarNames.append("\n"); + } + + notifyObservers(); +} + + +bool LLGestureMgr::isGestureActive(const LLUUID& item_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + item_map_t::iterator it = mActive.find(base_item_id); + return (it != mActive.end()); +} + + +bool LLGestureMgr::isGesturePlaying(const LLUUID& item_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + + item_map_t::iterator it = mActive.find(base_item_id); + if (it == mActive.end()) return false; + + LLMultiGesture* gesture = (*it).second; + if (!gesture) return false; + + return gesture->mPlaying; +} + +bool LLGestureMgr::isGesturePlaying(LLMultiGesture* gesture) +{ + if(!gesture) + { + return false; + } + + return gesture->mPlaying; +} + +void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + + item_map_t::iterator it = mActive.find(base_item_id); + if (it == mActive.end()) + { + LL_WARNS() << "replaceGesture for inactive gesture " << base_item_id << LL_ENDL; + return; + } + + LLMultiGesture* old_gesture = (*it).second; + stopGesture(old_gesture); + + mActive.erase(base_item_id); + + mActive[base_item_id] = new_gesture; + + // replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) + // replaces ids without repalcing gesture + if (old_gesture != new_gesture) + { + delete old_gesture; + old_gesture = NULL; + } + + if (asset_id.notNull()) + { + mLoadingCount = 1; + mDeactivateSimilarNames.clear(); + + LLLoadInfo* info = new LLLoadInfo; + info->mItemID = base_item_id; + info->mInformServer = true; + info->mDeactivateSimilar = false; + + const bool high_priority = true; + gAssetStorage->getAssetData(asset_id, + LLAssetType::AT_GESTURE, + onLoadComplete, + (void*)info, + high_priority); + } + + notifyObservers(); +} + +void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + + item_map_t::iterator it = LLGestureMgr::instance().mActive.find(base_item_id); + if (it == mActive.end()) + { + LL_WARNS() << "replaceGesture for inactive gesture " << base_item_id << LL_ENDL; + return; + } + + // mActive owns this gesture pointer, so clean up memory. + LLMultiGesture* gesture = (*it).second; + LLGestureMgr::instance().replaceGesture(base_item_id, gesture, new_asset_id); +} + +void LLGestureMgr::playGesture(LLMultiGesture* gesture, bool fromKeyPress) +{ + if (!gesture) return; + + // Reset gesture to first step + gesture->mCurrentStep = 0; + gesture->mTriggeredByKey = fromKeyPress; + + // Add to list of playing + gesture->mPlaying = true; + mPlaying.push_back(gesture); + + // Load all needed assets to minimize the delays + // when gesture is playing. + for (std::vector::iterator steps_it = gesture->mSteps.begin(); + steps_it != gesture->mSteps.end(); + ++steps_it) + { + LLGestureStep* step = *steps_it; + switch(step->getType()) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + const LLUUID& anim_id = anim_step->mAnimAssetID; + + // Don't request the animation if this step stops it or if it is already in the cache + if (!(anim_id.isNull() + || anim_step->mFlags & ANIM_FLAG_STOP + || gAssetStorage->hasLocalAsset(anim_id, LLAssetType::AT_ANIMATION))) + { + mLoadingAssets.insert(anim_id); + + LLUUID* id = new LLUUID(gAgentID); + gAssetStorage->getAssetData(anim_id, + LLAssetType::AT_ANIMATION, + onAssetLoadComplete, + (void *)id, + true); + } + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + const LLUUID& sound_id = sound_step->mSoundAssetID; + if (!(sound_id.isNull() + || gAssetStorage->hasLocalAsset(sound_id, LLAssetType::AT_SOUND))) + { + mLoadingAssets.insert(sound_id); + + gAssetStorage->getAssetData(sound_id, + LLAssetType::AT_SOUND, + onAssetLoadComplete, + NULL, + true); + } + break; + } + case STEP_CHAT: + case STEP_WAIT: + case STEP_EOF: + { + break; + } + default: + { + LL_WARNS() << "Unknown gesture step type: " << step->getType() << LL_ENDL; + } + } + } + + // And get it going + stepGesture(gesture); + + notifyObservers(); +} + + +// Convenience function that looks up the item_id for you. +void LLGestureMgr::playGesture(const LLUUID& item_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + + item_map_t::iterator it = mActive.find(base_item_id); + if (it == mActive.end()) return; + + LLMultiGesture* gesture = (*it).second; + if (!gesture) return; + + playGesture(gesture); +} + + +// Iterates through space delimited tokens in string, triggering any gestures found. +// Generates a revised string that has the found tokens replaced by their replacement strings +// and (as a minor side effect) has multiple spaces in a row replaced by single spaces. +bool LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::string* revised_string) +{ + std::string tokenized = utf8str; + + bool found_gestures = false; + bool first_token = true; + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep(" "); + tokenizer tokens(tokenized, sep); + tokenizer::iterator token_iter; + + for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + const char* cur_token = token_iter->c_str(); + LLMultiGesture* gesture = NULL; + + // Only pay attention to the first gesture in the string. + if( !found_gestures ) + { + // collect gestures that match + std::vector matching; + item_map_t::iterator it; + for (it = mActive.begin(); it != mActive.end(); ++it) + { + gesture = (*it).second; + + // Gesture asset data might not have arrived yet + if (!gesture) continue; + + if (LLStringUtil::compareInsensitive(gesture->mTrigger, cur_token) == 0) + { + matching.push_back(gesture); + } + + gesture = NULL; + } + + + if (matching.size() > 0) + { + // choose one at random + { + S32 random = ll_rand(matching.size()); + + gesture = matching[random]; + + playGesture(gesture); + + if (!gesture->mReplaceText.empty()) + { + if( !first_token ) + { + if (revised_string) + revised_string->append( " " ); + } + + // Don't muck with the user's capitalization if we don't have to. + if( LLStringUtil::compareInsensitive(cur_token, gesture->mReplaceText) == 0) + { + if (revised_string) + revised_string->append( cur_token ); + } + else + { + if (revised_string) + revised_string->append( gesture->mReplaceText ); + } + } + found_gestures = true; + } + } + } + + if(!gesture) + { + // This token doesn't match a gesture. Pass it through to the output. + if( !first_token ) + { + if (revised_string) + revised_string->append( " " ); + } + if (revised_string) + revised_string->append( cur_token ); + } + + first_token = false; + gesture = NULL; + } + return found_gestures; +} + + +bool LLGestureMgr::triggerGesture(KEY key, MASK mask) +{ + std::vector matching; + item_map_t::iterator it; + + // collect matching gestures + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + + // asset data might not have arrived yet + if (!gesture) continue; + + if (gesture->mKey == key + && gesture->mMask == mask + && gesture->mWaitingKeyRelease == false) + { + matching.push_back(gesture); + } + } + + // choose one and play it + if (matching.size() > 0) + { + U32 random = ll_rand(matching.size()); + + LLMultiGesture* gesture = matching[random]; + + playGesture(gesture, true); + return true; + } + return false; +} + + +bool LLGestureMgr::triggerGestureRelease(KEY key, MASK mask) +{ + std::vector matching; + item_map_t::iterator it; + + // collect matching gestures + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + + // asset data might not have arrived yet + if (!gesture) continue; + + if (gesture->mKey == key + && gesture->mMask == mask) + { + gesture->mKeyReleased = true; + } + } + + //If we found one, block. Otherwise tell them it's free to go. + return matching.size() > 0; +} + + +S32 LLGestureMgr::getPlayingCount() const +{ + return mPlaying.size(); +} + + +struct IsGesturePlaying +{ + bool operator()(const LLMultiGesture* gesture) const + { + return bool(gesture->mPlaying); + } +}; + +void LLGestureMgr::update() +{ + S32 i; + for (i = 0; i < (S32)mPlaying.size(); ++i) + { + stepGesture(mPlaying[i]); + } + + // Clear out gestures that are done, by moving all the + // ones that are still playing to the front. + std::vector::iterator new_end; + new_end = std::partition(mPlaying.begin(), + mPlaying.end(), + IsGesturePlaying()); + + // Something finished playing + if (new_end != mPlaying.end()) + { + // Delete the completed gestures that want deletion + std::vector::iterator it; + for (it = new_end; it != mPlaying.end(); ++it) + { + LLMultiGesture* gesture = *it; + + if (gesture->mDoneCallback) + { + gesture->mDoneCallback(gesture, gesture->mCallbackData); + + // callback might have deleted gesture, can't + // rely on this pointer any more + gesture = NULL; + } + } + + // And take done gestures out of the playing list + mPlaying.erase(new_end, mPlaying.end()); + + notifyObservers(); + } +} + + +// Run all steps until you're either done or hit a wait. +void LLGestureMgr::stepGesture(LLMultiGesture* gesture) +{ + if (!gesture) + { + return; + } + if (!isAgentAvatarValid() || hasLoadingAssets(gesture)) return; + + // Of the ones that started playing, have any stopped? + + std::set::iterator gest_it; + for (gest_it = gesture->mPlayingAnimIDs.begin(); + gest_it != gesture->mPlayingAnimIDs.end(); + ) + { + // look in signaled animations (simulator's view of what is + // currently playing. + LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); + if (play_it != gAgentAvatarp->mSignaledAnimations.end()) + { + ++gest_it; + } + else + { + // not found, so not currently playing or scheduled to play + // delete from the triggered set + gesture->mPlayingAnimIDs.erase(gest_it++); + } + } + + // Of all the animations that we asked the sim to start for us, + // pick up the ones that have actually started. + for (gest_it = gesture->mRequestedAnimIDs.begin(); + gest_it != gesture->mRequestedAnimIDs.end(); + ) + { + LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); + if (play_it != gAgentAvatarp->mSignaledAnimations.end()) + { + // Hooray, this animation has started playing! + // Copy into playing. + gesture->mPlayingAnimIDs.insert(*gest_it); + gesture->mRequestedAnimIDs.erase(gest_it++); + } + else + { + // nope, not playing yet + ++gest_it; + } + } + + // Run the current steps + bool waiting = false; + while (!waiting && gesture->mPlaying) + { + // Get the current step, if there is one. + // Otherwise enter the waiting at end state. + LLGestureStep* step = NULL; + if (gesture->mCurrentStep < (S32)gesture->mSteps.size()) + { + step = gesture->mSteps[gesture->mCurrentStep]; + llassert(step != NULL); + } + else + { + // step stays null, we're off the end + gesture->mWaitingAtEnd = true; + } + + + // If we're waiting at the end, wait for all gestures to stop + // playing. + // TODO: Wait for all sounds to complete as well. + if (gesture->mWaitingAtEnd) + { + // Neither do we have any pending requests, nor are they + // still playing. + if ((gesture->mRequestedAnimIDs.empty() + && gesture->mPlayingAnimIDs.empty())) + { + // all animations are done playing + gesture->mWaitingAtEnd = false; + gesture->mPlaying = false; + } + else + { + waiting = true; + } + continue; + } + + // If we're waiting a fixed amount of time, check for timer + // expiration. + if (gesture->mWaitingKeyRelease) + { + // We're waiting for a certain amount of time to pass + if (gesture->mKeyReleased) + { + // wait is done, continue execution + gesture->mWaitingKeyRelease = false; + gesture->mCurrentStep++; + } + else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_KEY_SECS) + { + LL_INFOS("GestureMgr") << "Waited too long for key release, continuing gesture." + << LL_ENDL; + gesture->mWaitingKeyRelease = false; + gesture->mCurrentStep++; + } + else + { + // we're waiting, so execution is done for now + waiting = true; + } + continue; + } + + // If we're waiting on our animations to stop, poll for + // completion. + if (gesture->mWaitingAnimations) + { + // Neither do we have any pending requests, nor are they + // still playing. + if ((gesture->mRequestedAnimIDs.empty() + && gesture->mPlayingAnimIDs.empty())) + { + // all animations are done playing + gesture->mWaitingAnimations = false; + gesture->mCurrentStep++; + } + else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS) + { + // we've waited too long for an animation + LL_INFOS("GestureMgr") << "Waited too long for animations to stop, continuing gesture." + << LL_ENDL; + gesture->mWaitingAnimations = false; + gesture->mCurrentStep++; + } + else + { + waiting = true; + } + continue; + } + + // If we're waiting a fixed amount of time, check for timer + // expiration. + if (gesture->mWaitingTimer) + { + // We're waiting for a certain amount of time to pass + LLGestureStepWait* wait_step = (LLGestureStepWait*)step; + + F32 elapsed = gesture->mWaitTimer.getElapsedTimeF32(); + if (elapsed > wait_step->mWaitSeconds) + { + // wait is done, continue execution + gesture->mWaitingTimer = false; + gesture->mCurrentStep++; + } + else + { + // we're waiting, so execution is done for now + waiting = true; + } + continue; + } + + // Not waiting, do normal execution + runStep(gesture, step); + } +} + + +void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) +{ + switch(step->getType()) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + if (anim_step->mAnimAssetID.isNull()) + { + gesture->mCurrentStep++; + } + + if (anim_step->mFlags & ANIM_FLAG_STOP) + { + gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_STOP); + // remove it from our request set in case we just requested it + std::set::iterator set_it = gesture->mRequestedAnimIDs.find(anim_step->mAnimAssetID); + if (set_it != gesture->mRequestedAnimIDs.end()) + { + gesture->mRequestedAnimIDs.erase(set_it); + } + } + else + { + gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_START); + // Indicate that we've requested this animation to play as + // part of this gesture (but it won't start playing for at + // least one round-trip to simulator). + gesture->mRequestedAnimIDs.insert(anim_step->mAnimAssetID); + } + gesture->mCurrentStep++; + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + const LLUUID& sound_id = sound_step->mSoundAssetID; + const F32 volume = 1.f; + send_sound_trigger(sound_id, volume); + gesture->mCurrentStep++; + break; + } + case STEP_CHAT: + { + LLGestureStepChat* chat_step = (LLGestureStepChat*)step; + std::string chat_text = chat_step->mChatText; + // Don't animate the nodding, as this might not blend with + // other playing animations. + + const bool animate = false; + + (LLFloaterReg::getTypedInstance("nearby_chat"))-> + sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); + + gesture->mCurrentStep++; + break; + } + case STEP_WAIT: + { + LLGestureStepWait* wait_step = (LLGestureStepWait*)step; + if (gesture->mTriggeredByKey // Only wait here IF we were triggered by a key! + && gesture->mWaitingKeyRelease == false // We can only do this once! Prevent gestures infinitely running + && wait_step->mFlags & WAIT_FLAG_KEY_RELEASE) + { + // Lets wait for the key release first so we don't hold up re-presses + gesture->mWaitingKeyRelease = true; + gesture->mKeyReleased = false; + // Use the wait timer as a deadlock breaker for key release waits. + gesture->mWaitTimer.reset(); + } + else if (wait_step->mFlags & WAIT_FLAG_TIME) + { + gesture->mWaitingTimer = true; + gesture->mWaitTimer.reset(); + } + else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM) + { + gesture->mWaitingAnimations = true; + // Use the wait timer as a deadlock breaker for animation waits. + gesture->mWaitTimer.reset(); + } + else + { + gesture->mCurrentStep++; + } + // Don't increment instruction pointer until wait is complete. + break; + } + default: + { + break; + } + } +} + + +// static +void LLGestureMgr::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLLoadInfo* info = (LLLoadInfo*)user_data; + + LLUUID item_id = info->mItemID; + bool inform_server = info->mInformServer; + bool deactivate_similar = info->mDeactivateSimilar; + + delete info; + info = NULL; + LLGestureMgr& self = LLGestureMgr::instance(); + self.mLoadingCount--; + + if (0 == status) + { + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); + S32 size = file.getSize(); + + std::vector buffer(size+1); + + file.read((U8*)&buffer[0], size); + // ensure there's a trailing NULL so strlen will work. + buffer[size] = '\0'; + + LLMultiGesture* gesture = new LLMultiGesture(); + + LLDataPackerAsciiBuffer dp(&buffer[0], size+1); + bool ok = gesture->deserialize(dp); + + if (ok) + { + if (deactivate_similar) + { + self.deactivateSimilarGestures(gesture, item_id); + + // Display deactivation message if this was the last of the bunch. + if (self.mLoadingCount == 0 + && self.mDeactivateSimilarNames.length() > 0) + { + // we're done with this set of deactivations + LLSD args; + args["NAMES"] = self.mDeactivateSimilarNames; + LLNotificationsUtil::add("DeactivatedGesturesTrigger", args); + } + } + + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if(item) + { + gesture->mName = item->getName(); + } + else + { + // Watch this item and set gesture name when item exists in inventory + self.setFetchID(item_id); + self.startFetch(); + } + + item_map_t::iterator it = self.mActive.find(item_id); + if (it == self.mActive.end()) + { + // Gesture is supposed to be present, active, but NULL + LL_DEBUGS("GestureMgr") << "Gesture " << item_id << " not found in active list" << LL_ENDL; + } + else + { + LLMultiGesture* old_gesture = (*it).second; + if (old_gesture && old_gesture != gesture) + { + LL_DEBUGS("GestureMgr") << "Received dupplicate " << item_id << " callback" << LL_ENDL; + // In case somebody managest to activate, deactivate and + // then activate gesture again, before asset finishes loading. + // LLLoadInfo will have a different pointer, asset storage will + // see it as a different request, resulting in two callbacks. + + // deactivateSimilarGestures() did not turn this one off + // because of matching item_id + self.stopGesture(old_gesture); + + self.mActive.erase(item_id); + delete old_gesture; + old_gesture = NULL; + } + } + + self.mActive[item_id] = gesture; + + // Everything has been successful. Add to the active list. + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + + if (inform_server) + { + // Inform the database of this change + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("ActivateGestures"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addU32("Flags", 0x0); + + msg->nextBlock("Data"); + msg->addUUID("ItemID", item_id); + msg->addUUID("AssetID", asset_uuid); + msg->addU32("GestureFlags", 0x0); + + gAgent.sendReliableMessage(); + } + callback_map_t::iterator i_cb = self.mCallbackMap.find(item_id); + + if(i_cb != self.mCallbackMap.end()) + { + i_cb->second(gesture); + self.mCallbackMap.erase(i_cb); + } + + self.notifyObservers(); + } + else + { + LL_WARNS("GestureMgr") << "Unable to load gesture" << LL_ENDL; + + item_map_t::iterator it = self.mActive.find(item_id); + if (it != self.mActive.end()) + { + LLMultiGesture* old_gesture = (*it).second; + if (old_gesture) + { + // Shouldn't happen, just in case + LL_WARNS("GestureMgr") << "Gesture " << item_id << " existed when it shouldn't" << LL_ENDL; + + self.stopGesture(old_gesture); + delete old_gesture; + old_gesture = NULL; + } + self.mActive.erase(item_id); + } + + delete gesture; + gesture = NULL; + } + } + else + { + if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + LLDelayedGestureError::gestureMissing( item_id ); + } + else + { + LLDelayedGestureError::gestureFailedToLoad( item_id ); + } + + LL_WARNS("GestureMgr") << "Problem loading gesture: " << status << LL_ENDL; + + item_map_t::iterator it = self.mActive.find(item_id); + if (it != self.mActive.end()) + { + LLMultiGesture* old_gesture = (*it).second; + if (old_gesture) + { + // Shouldn't happen, just in case + LL_WARNS("GestureMgr") << "Gesture " << item_id << " existed when it shouldn't" << LL_ENDL; + + self.stopGesture(old_gesture); + delete old_gesture; + old_gesture = NULL; + } + self.mActive.erase(item_id); + } + } +} + +// static +void LLGestureMgr::onAssetLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LLGestureMgr& self = LLGestureMgr::instance(); + + // Complete the asset loading process depending on the type and + // remove the asset id from pending downloads list. + switch(type) + { + case LLAssetType::AT_ANIMATION: + { + LLKeyframeMotion::onLoadComplete(asset_uuid, type, user_data, status, ext_status); + + self.mLoadingAssets.erase(asset_uuid); + + break; + } + case LLAssetType::AT_SOUND: + { + LLAudioEngine::assetCallback(asset_uuid, type, user_data, status, ext_status); + + self.mLoadingAssets.erase(asset_uuid); + + break; + } + default: + { + LL_WARNS() << "Unexpected asset type: " << type << LL_ENDL; + + // We don't want to return from this callback without + // an animation or sound callback being fired + // and *user_data handled to avoid memory leaks. + llassert(type == LLAssetType::AT_ANIMATION || type == LLAssetType::AT_SOUND); + } + } +} + +// static +bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture) +{ + LLGestureMgr& self = LLGestureMgr::instance(); + + for (std::vector::iterator steps_it = gesture->mSteps.begin(); + steps_it != gesture->mSteps.end(); + ++steps_it) + { + LLGestureStep* step = *steps_it; + switch(step->getType()) + { + case STEP_ANIMATION: + { + LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; + const LLUUID& anim_id = anim_step->mAnimAssetID; + + if (!(anim_id.isNull() + || anim_step->mFlags & ANIM_FLAG_STOP + || self.mLoadingAssets.find(anim_id) == self.mLoadingAssets.end())) + { + return true; + } + break; + } + case STEP_SOUND: + { + LLGestureStepSound* sound_step = (LLGestureStepSound*)step; + const LLUUID& sound_id = sound_step->mSoundAssetID; + + if (!(sound_id.isNull() + || self.mLoadingAssets.find(sound_id) == self.mLoadingAssets.end())) + { + return true; + } + break; + } + case STEP_CHAT: + case STEP_WAIT: + case STEP_EOF: + { + break; + } + default: + { + LL_WARNS() << "Unknown gesture step type: " << step->getType() << LL_ENDL; + } + } + } + + return false; +} + +void LLGestureMgr::stopGesture(LLMultiGesture* gesture) +{ + if (!gesture) return; + + // Stop any animations that this gesture is currently playing + std::set::const_iterator set_it; + for (set_it = gesture->mRequestedAnimIDs.begin(); set_it != gesture->mRequestedAnimIDs.end(); ++set_it) + { + const LLUUID& anim_id = *set_it; + gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); + } + for (set_it = gesture->mPlayingAnimIDs.begin(); set_it != gesture->mPlayingAnimIDs.end(); ++set_it) + { + const LLUUID& anim_id = *set_it; + gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); + } + + std::vector::iterator it; + it = std::find(mPlaying.begin(), mPlaying.end(), gesture); + while (it != mPlaying.end()) + { + mPlaying.erase(it); + it = std::find(mPlaying.begin(), mPlaying.end(), gesture); + } + + gesture->reset(); + + if (gesture->mDoneCallback) + { + gesture->mDoneCallback(gesture, gesture->mCallbackData); + + // callback might have deleted gesture, can't + // rely on this pointer any more + gesture = NULL; + } + + notifyObservers(); +} + + +void LLGestureMgr::stopGesture(const LLUUID& item_id) +{ + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + + item_map_t::iterator it = mActive.find(base_item_id); + if (it == mActive.end()) return; + + LLMultiGesture* gesture = (*it).second; + if (!gesture) return; + + stopGesture(gesture); +} + + +void LLGestureMgr::addObserver(LLGestureManagerObserver* observer) +{ + mObservers.push_back(observer); +} + +void LLGestureMgr::removeObserver(LLGestureManagerObserver* observer) +{ + std::vector::iterator it; + it = std::find(mObservers.begin(), mObservers.end(), observer); + if (it != mObservers.end()) + { + mObservers.erase(it); + } +} + +// Call this method when it's time to update everyone on a new state. +// Copy the list because an observer could respond by removing itself +// from the list. +void LLGestureMgr::notifyObservers() +{ + LL_DEBUGS() << "LLGestureMgr::notifyObservers" << LL_ENDL; + + for(std::vector::iterator iter = mObservers.begin(); + iter != mObservers.end(); + ++iter) + { + LLGestureManagerObserver* observer = (*iter); + observer->changed(); + } +} + +bool LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) +{ + S32 in_len = in_str.length(); + + //return whole trigger, if received text equals to it + item_map_t::iterator it; + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { + const std::string& trigger = gesture->getTrigger(); + if (!LLStringUtil::compareInsensitive(in_str, trigger)) + { + *out_str = trigger; + return true; + } + } + } + + //return common chars, if more than one trigger matches the prefix + std::string rest_of_match = ""; + std::string buf = ""; + for (it = mActive.begin(); it != mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { + const std::string& trigger = gesture->getTrigger(); + + if (in_len > (S32)trigger.length()) + { + // too short, bail out + continue; + } + + std::string trigger_trunc = trigger; + LLStringUtil::truncate(trigger_trunc, in_len); + if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc)) + { + if (rest_of_match.compare("") == 0) + { + rest_of_match = trigger.substr(in_str.size()); + } + std::string cur_rest_of_match = trigger.substr(in_str.size()); + buf = ""; + S32 i=0; + + while (ipush_back(it->first); + } +} + +void LLGestureMgr::done() +{ + bool notify = false; + for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) + { + if(it->second && it->second->mName.empty()) + { + LLViewerInventoryItem* item = gInventory.getItem(it->first); + if(item) + { + it->second->mName = item->getName(); + notify = true; + } + } + } + if(notify) + { + notifyObservers(); + } +} + + -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/newview/llgesturemgr.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra/newview/llgesturemgr.cpp') diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 2ac99a2f16..8ee11cdbd2 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -671,7 +671,7 @@ bool LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::strin { // choose one at random { - S32 random = ll_rand(matching.size()); + S32 random = ll_rand(static_cast(matching.size())); gesture = matching[random]; @@ -745,7 +745,7 @@ bool LLGestureMgr::triggerGesture(KEY key, MASK mask) // choose one and play it if (matching.size() > 0) { - U32 random = ll_rand(matching.size()); + U32 random = ll_rand(static_cast(matching.size())); LLMultiGesture* gesture = matching[random]; @@ -783,7 +783,7 @@ bool LLGestureMgr::triggerGestureRelease(KEY key, MASK mask) S32 LLGestureMgr::getPlayingCount() const { - return mPlaying.size(); + return static_cast(mPlaying.size()); } @@ -1462,7 +1462,7 @@ void LLGestureMgr::notifyObservers() bool LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) { - S32 in_len = in_str.length(); + auto in_len = in_str.length(); //return whole trigger, if received text equals to it item_map_t::iterator it; @@ -1490,7 +1490,7 @@ bool LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) { const std::string& trigger = gesture->getTrigger(); - if (in_len > (S32)trigger.length()) + if (in_len > trigger.length()) { // too short, bail out continue; -- cgit v1.2.3