llgesturemgr.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llgesturemgr.h"
00035 
00036 // system
00037 #include <functional>
00038 #include <algorithm>
00039 #include <boost/tokenizer.hpp>
00040 
00041 // library
00042 #include "lldatapacker.h"
00043 #include "llinventory.h"
00044 #include "llmultigesture.h"
00045 #include "llstl.h"
00046 #include "llstring.h"   // todo: remove
00047 #include "llvfile.h"
00048 #include "message.h"
00049 
00050 // newview
00051 #include "llagent.h"
00052 #include "llchatbar.h"
00053 #include "llinventorymodel.h"
00054 #include "llnotify.h"
00055 #include "llviewermessage.h"
00056 #include "llvoavatar.h"
00057 #include "llviewerstats.h"
00058 #include "viewer.h"
00059 
00060 LLGestureManager gGestureManager;
00061 
00062 // Longest time, in seconds, to wait for all animations to stop playing
00063 const F32 MAX_WAIT_ANIM_SECS = 30.f;
00064 
00065 
00066 // Lightweight constructor.
00067 // init() does the heavy lifting.
00068 LLGestureManager::LLGestureManager()
00069 :       mValid(FALSE),
00070         mPlaying(),
00071         mActive(),
00072         mLoadingCount(0)
00073 { }
00074 
00075 
00076 // We own the data for gestures, so clean them up.
00077 LLGestureManager::~LLGestureManager()
00078 {
00079         item_map_t::iterator it;
00080         for (it = mActive.begin(); it != mActive.end(); ++it)
00081         {
00082                 LLMultiGesture* gesture = (*it).second;
00083 
00084                 delete gesture;
00085                 gesture = NULL;
00086         }
00087 }
00088 
00089 
00090 void LLGestureManager::init()
00091 {
00092         // TODO
00093 }
00094 
00095 
00096 // Use this version when you have the item_id but not the asset_id,
00097 // and you KNOW the inventory is loaded.
00098 void LLGestureManager::activateGesture(const LLUUID& item_id)
00099 {
00100         LLViewerInventoryItem* item = gInventory.getItem(item_id);
00101         if (!item) return;
00102 
00103         LLUUID asset_id = item->getAssetUUID();
00104 
00105         mLoadingCount = 1;
00106         mDeactivateSimilarNames.clear();
00107 
00108         const BOOL inform_server = TRUE;
00109         const BOOL deactivate_similar = FALSE; 
00110         activateGestureWithAsset(item_id, asset_id, inform_server, deactivate_similar);
00111 }
00112 
00113 
00114 void LLGestureManager::activateGestures(LLViewerInventoryItem::item_array_t& items)
00115 {
00116         // Load up the assets
00117         S32 count = 0;
00118         LLViewerInventoryItem::item_array_t::const_iterator it;
00119         for (it = items.begin(); it != items.end(); ++it)
00120         {
00121                 LLViewerInventoryItem* item = *it;
00122 
00123                 if (isGestureActive(item->getUUID()))
00124                 {
00125                         continue;
00126                 }
00127                 else 
00128                 { // Make gesture active and persistent through login sessions.  -spatters 07-12-06
00129                         activateGesture(item->getUUID());
00130                 }
00131 
00132                 count++;
00133         }
00134 
00135         mLoadingCount = count;
00136         mDeactivateSimilarNames.clear();
00137 
00138         for (it = items.begin(); it != items.end(); ++it)
00139         {
00140                 LLViewerInventoryItem* item = *it;
00141 
00142                 if (isGestureActive(item->getUUID()))
00143                 {
00144                         continue;
00145                 }
00146 
00147                 // Don't inform server, we'll do that in bulk
00148                 const BOOL no_inform_server = FALSE;
00149                 const BOOL deactivate_similar = TRUE;
00150                 activateGestureWithAsset(item->getUUID(), item->getAssetUUID(),
00151                                                                  no_inform_server,
00152                                                                  deactivate_similar);
00153         }
00154 
00155         // Inform the database of this change
00156         LLMessageSystem* msg = gMessageSystem;
00157 
00158         BOOL start_message = TRUE;
00159 
00160         for (it = items.begin(); it != items.end(); ++it)
00161         {
00162                 LLViewerInventoryItem* item = *it;
00163 
00164                 if (isGestureActive(item->getUUID()))
00165                 {
00166                         continue;
00167                 }
00168 
00169                 if (start_message)
00170                 {
00171                         msg->newMessage("ActivateGestures");
00172                         msg->nextBlock("AgentData");
00173                         msg->addUUID("AgentID", gAgent.getID());
00174                         msg->addUUID("SessionID", gAgent.getSessionID());
00175                         msg->addU32("Flags", 0x0);
00176                         start_message = FALSE;
00177                 }
00178                 
00179                 msg->nextBlock("Data");
00180                 msg->addUUID("ItemID", item->getUUID());
00181                 msg->addUUID("AssetID", item->getAssetUUID());
00182                 msg->addU32("GestureFlags", 0x0);
00183 
00184                 if (msg->getCurrentSendTotal() > MTUBYTES)
00185                 {
00186                         gAgent.sendReliableMessage();
00187                         start_message = TRUE;
00188                 }
00189         }
00190 
00191         if (!start_message)
00192         {
00193                 gAgent.sendReliableMessage();
00194         }
00195 }
00196 
00197 
00198 struct LLLoadInfo
00199 {
00200         LLUUID mItemID;
00201         BOOL mInformServer;
00202         BOOL mDeactivateSimilar;
00203 };
00204 
00205 // If inform_server is true, will send a message upstream to update
00206 // the user_gesture_active table.
00207 void LLGestureManager::activateGestureWithAsset(const LLUUID& item_id,
00208                                                                                                 const LLUUID& asset_id,
00209                                                                                                 BOOL inform_server,
00210                                                                                                 BOOL deactivate_similar)
00211 {
00212         if( !gAssetStorage )
00213         {
00214                 llwarns << "LLGestureManager::activateGestureWithAsset without valid gAssetStorage" << llendl;
00215                 return;
00216         }
00217         // If gesture is already active, nothing to do.
00218         if (isGestureActive(item_id))
00219         {
00220                 llwarns << "Tried to loadGesture twice " << item_id << llendl;
00221                 return;
00222         }
00223 
00224 //      if (asset_id.isNull())
00225 //      {
00226 //              llwarns << "loadGesture() - gesture has no asset" << llendl;
00227 //              return;
00228 //      }
00229 
00230         // For now, put NULL into the item map.  We'll build a gesture
00231         // class object when the asset data arrives.
00232         mActive[item_id] = NULL;
00233 
00234         // Copy the UUID
00235         if (asset_id.notNull())
00236         {
00237                 LLLoadInfo* info = new LLLoadInfo;
00238                 info->mItemID = item_id;
00239                 info->mInformServer = inform_server;
00240                 info->mDeactivateSimilar = deactivate_similar;
00241 
00242                 const BOOL high_priority = TRUE;
00243                 gAssetStorage->getAssetData(asset_id,
00244                                                                         LLAssetType::AT_GESTURE,
00245                                                                         onLoadComplete,
00246                                                                         (void*)info,
00247                                                                         high_priority);
00248         }
00249         else
00250         {
00251                 notifyObservers();
00252         }
00253 }
00254 
00255 
00256 void LLGestureManager::deactivateGesture(const LLUUID& item_id)
00257 {
00258         item_map_t::iterator it = mActive.find(item_id);
00259         if (it == mActive.end())
00260         {
00261                 llwarns << "deactivateGesture for inactive gesture " << item_id << llendl;
00262                 return;
00263         }
00264 
00265         // mActive owns this gesture pointer, so clean up memory.
00266         LLMultiGesture* gesture = (*it).second;
00267 
00268         // Can be NULL gestures in the map
00269         if (gesture)
00270         {
00271                 stopGesture(gesture);
00272 
00273                 delete gesture;
00274                 gesture = NULL;
00275         }
00276 
00277         mActive.erase(it);
00278         gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
00279 
00280         // Inform the database of this change
00281         LLMessageSystem* msg = gMessageSystem;
00282         msg->newMessage("DeactivateGestures");
00283         msg->nextBlock("AgentData");
00284         msg->addUUID("AgentID", gAgent.getID());
00285         msg->addUUID("SessionID", gAgent.getSessionID());
00286         msg->addU32("Flags", 0x0);
00287         
00288         msg->nextBlock("Data");
00289         msg->addUUID("ItemID", item_id);
00290         msg->addU32("GestureFlags", 0x0);
00291 
00292         gAgent.sendReliableMessage();
00293 
00294         notifyObservers();
00295 }
00296 
00297 
00298 void LLGestureManager::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id)
00299 {
00300         std::vector<LLUUID> gest_item_ids;
00301 
00302         // Deactivate all gestures that match
00303         item_map_t::iterator it;
00304         for (it = mActive.begin(); it != mActive.end(); )
00305         {
00306                 const LLUUID& item_id = (*it).first;
00307                 LLMultiGesture* gest = (*it).second;
00308 
00309                 // Don't deactivate the gesture we are looking for duplicates of
00310                 // (for replaceGesture)
00311                 if (!gest || item_id == in_item_id) 
00312                 {
00313                         // legal, can have null pointers in list
00314                         ++it;
00315                 }
00316                 else if ((!gest->mTrigger.empty() && gest->mTrigger == in->mTrigger)
00317                                  || (gest->mKey != KEY_NONE && gest->mKey == in->mKey && gest->mMask == in->mMask))
00318                 {
00319                         gest_item_ids.push_back(item_id);
00320 
00321                         stopGesture(gest);
00322 
00323                         delete gest;
00324                         gest = NULL;
00325 
00326                         mActive.erase(it++);
00327                         gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
00328 
00329                 }
00330                 else
00331                 {
00332                         ++it;
00333                 }
00334         }
00335 
00336         // Inform database of the change
00337         LLMessageSystem* msg = gMessageSystem;
00338         BOOL start_message = TRUE;
00339         std::vector<LLUUID>::const_iterator vit = gest_item_ids.begin();
00340         while (vit != gest_item_ids.end())
00341         {
00342                 if (start_message)
00343                 {
00344                         msg->newMessage("DeactivateGestures");
00345                         msg->nextBlock("AgentData");
00346                         msg->addUUID("AgentID", gAgent.getID());
00347                         msg->addUUID("SessionID", gAgent.getSessionID());
00348                         msg->addU32("Flags", 0x0);
00349                         start_message = FALSE;
00350                 }
00351         
00352                 msg->nextBlock("Data");
00353                 msg->addUUID("ItemID", *vit);
00354                 msg->addU32("GestureFlags", 0x0);
00355 
00356                 if (msg->getCurrentSendTotal() > MTUBYTES)
00357                 {
00358                         gAgent.sendReliableMessage();
00359                         start_message = TRUE;
00360                 }
00361 
00362                 ++vit;
00363         }
00364 
00365         if (!start_message)
00366         {
00367                 gAgent.sendReliableMessage();
00368         }
00369 
00370         // Add to the list of names for the user.
00371         for (vit = gest_item_ids.begin(); vit != gest_item_ids.end(); ++vit)
00372         {
00373                 LLViewerInventoryItem* item = gInventory.getItem(*vit);
00374                 if (!item) continue;
00375 
00376                 mDeactivateSimilarNames.append(item->getName());
00377                 mDeactivateSimilarNames.append("\n");
00378         }
00379 
00380         notifyObservers();
00381 }
00382 
00383 
00384 BOOL LLGestureManager::isGestureActive(const LLUUID& item_id)
00385 {
00386         item_map_t::iterator it = mActive.find(item_id);
00387         return (it != mActive.end());
00388 }
00389 
00390 
00391 BOOL LLGestureManager::isGesturePlaying(const LLUUID& item_id)
00392 {
00393         item_map_t::iterator it = mActive.find(item_id);
00394         if (it == mActive.end()) return FALSE;
00395 
00396         LLMultiGesture* gesture = (*it).second;
00397         if (!gesture) return FALSE;
00398 
00399         return gesture->mPlaying;
00400 }
00401 
00402 void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id)
00403 {
00404         item_map_t::iterator it = mActive.find(item_id);
00405         if (it == mActive.end())
00406         {
00407                 llwarns << "replaceGesture for inactive gesture " << item_id << llendl;
00408                 return;
00409         }
00410 
00411         LLMultiGesture* old_gesture = (*it).second;
00412         stopGesture(old_gesture);
00413 
00414         mActive.erase(item_id);
00415 
00416         mActive[item_id] = new_gesture;
00417 
00418         delete old_gesture;
00419         old_gesture = NULL;
00420 
00421         if (asset_id.notNull())
00422         {
00423                 mLoadingCount = 1;
00424                 mDeactivateSimilarNames.clear();
00425 
00426                 LLLoadInfo* info = new LLLoadInfo;
00427                 info->mItemID = item_id;
00428                 info->mInformServer = TRUE;
00429                 info->mDeactivateSimilar = FALSE;
00430 
00431                 const BOOL high_priority = TRUE;
00432                 gAssetStorage->getAssetData(asset_id,
00433                                                                         LLAssetType::AT_GESTURE,
00434                                                                         onLoadComplete,
00435                                                                         (void*)info,
00436                                                                         high_priority);
00437         }
00438 
00439         notifyObservers();
00440 }
00441 
00442 void LLGestureManager::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id)
00443 {
00444         item_map_t::iterator it = gGestureManager.mActive.find(item_id);
00445         if (it == mActive.end())
00446         {
00447                 llwarns << "replaceGesture for inactive gesture " << item_id << llendl;
00448                 return;
00449         }
00450 
00451         // mActive owns this gesture pointer, so clean up memory.
00452         LLMultiGesture* gesture = (*it).second;
00453         gGestureManager.replaceGesture(item_id, gesture, new_asset_id);
00454 }
00455 
00456 void LLGestureManager::playGesture(LLMultiGesture* gesture)
00457 {
00458         if (!gesture) return;
00459 
00460         // Reset gesture to first step
00461         gesture->mCurrentStep = 0;
00462 
00463         // Add to list of playing
00464         gesture->mPlaying = TRUE;
00465         mPlaying.push_back(gesture);
00466 
00467         // And get it going
00468         stepGesture(gesture);
00469 
00470         notifyObservers();
00471 }
00472 
00473 
00474 // Convenience function that looks up the item_id for you.
00475 void LLGestureManager::playGesture(const LLUUID& item_id)
00476 {
00477         item_map_t::iterator it = mActive.find(item_id);
00478         if (it == mActive.end()) return;
00479 
00480         LLMultiGesture* gesture = (*it).second;
00481         if (!gesture) return;
00482 
00483         playGesture(gesture);
00484 }
00485 
00486 
00487 // Iterates through space delimited tokens in string, triggering any gestures found.
00488 // Generates a revised string that has the found tokens replaced by their replacement strings
00489 // and (as a minor side effect) has multiple spaces in a row replaced by single spaces.
00490 BOOL LLGestureManager::triggerAndReviseString(const std::string &utf8str, std::string* revised_string)
00491 {
00492         LLString tokenized = LLString(utf8str.c_str());
00493 
00494         BOOL found_gestures = FALSE;
00495         BOOL first_token = TRUE;
00496 
00497         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00498         boost::char_separator<char> sep(" ");
00499         tokenizer tokens(tokenized, sep);
00500         tokenizer::iterator token_iter;
00501 
00502         for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
00503         {
00504                 const char* cur_token = token_iter->c_str();
00505                 LLMultiGesture* gesture = NULL;
00506 
00507                 // Only pay attention to the first gesture in the string.
00508                 if( !found_gestures )
00509                 {
00510                         LLString cur_token_lower = cur_token;
00511                         LLString::toLower(cur_token_lower);
00512 
00513                         // collect gestures that match
00514                         std::vector <LLMultiGesture *> matching;
00515                         item_map_t::iterator it;
00516                         for (it = mActive.begin(); it != mActive.end(); ++it)
00517                         {
00518                                 gesture = (*it).second;
00519 
00520                                 // Gesture asset data might not have arrived yet
00521                                 if (!gesture) continue;
00522                                 
00523                                 if (!stricmp(gesture->mTrigger.c_str(), cur_token_lower.c_str()))
00524                                 {
00525                                         matching.push_back(gesture);
00526                                 }
00527                                 
00528                                 gesture = NULL;
00529                         }
00530 
00531                         
00532                         if (matching.size() > 0)
00533                         {
00534                                 // choose one at random
00535                                 {
00536                                         S32 random = ll_rand(matching.size());
00537 
00538                                         gesture = matching[random];
00539                                         
00540                                         playGesture(gesture);
00541 
00542                                         if (!gesture->mReplaceText.empty())
00543                                         {
00544                                                 if( !first_token )
00545                                                 {
00546                                                         if (revised_string)
00547                                                                 revised_string->append( " " );
00548                                                 }
00549 
00550                                                 // Don't muck with the user's capitalization if we don't have to.
00551                                                 LLString output = gesture->mReplaceText.c_str();
00552                                                 LLString output_lower = output;
00553                                                 LLString::toLower(output_lower);
00554                                                 if( cur_token_lower == output_lower )
00555                                                 {
00556                                                         if (revised_string)
00557                                                                 revised_string->append( cur_token );
00558                                                 }
00559                                                 else
00560                                                 {
00561                                                         if (revised_string)
00562                                                                 revised_string->append( output );
00563                                                 }
00564                                         }
00565                                         found_gestures = TRUE;
00566                                 }
00567                         }
00568                 }
00569                 
00570                 if(!gesture)
00571                 {
00572                         // This token doesn't match a gesture.  Pass it through to the output.
00573                         if( !first_token )
00574                         {
00575                                 if (revised_string)
00576                                         revised_string->append( " " );
00577                         }
00578                         if (revised_string)
00579                                 revised_string->append( cur_token );
00580                 }
00581 
00582                 first_token = FALSE;
00583                 gesture = NULL;
00584         }
00585         return found_gestures;
00586 }
00587 
00588 
00589 BOOL LLGestureManager::triggerGesture(KEY key, MASK mask)
00590 {
00591         std::vector <LLMultiGesture *> matching;
00592         item_map_t::iterator it;
00593 
00594         // collect matching gestures
00595         for (it = mActive.begin(); it != mActive.end(); ++it)
00596         {
00597                 LLMultiGesture* gesture = (*it).second;
00598 
00599                 // asset data might not have arrived yet
00600                 if (!gesture) continue;
00601 
00602                 if (gesture->mKey == key
00603                         && gesture->mMask == mask)
00604                 {
00605                         matching.push_back(gesture);
00606                 }
00607         }
00608 
00609         // choose one and play it
00610         if (matching.size() > 0)
00611         {
00612                 U32 random = ll_rand(matching.size());
00613                 
00614                 LLMultiGesture* gesture = matching[random];
00615                         
00616                 playGesture(gesture);
00617                 return TRUE;
00618         }
00619         return FALSE;
00620 }
00621 
00622 
00623 S32 LLGestureManager::getPlayingCount() const
00624 {
00625         return mPlaying.size();
00626 }
00627 
00628 
00629 struct IsGesturePlaying : public std::unary_function<LLMultiGesture*, bool>
00630 {
00631         bool operator()(const LLMultiGesture* gesture) const
00632         {
00633                 return gesture->mPlaying ? true : false;
00634         }
00635 };
00636 
00637 void LLGestureManager::update()
00638 {
00639         S32 i;
00640         for (i = 0; i < (S32)mPlaying.size(); ++i)
00641         {
00642                 stepGesture(mPlaying[i]);
00643         }
00644 
00645         // Clear out gestures that are done, by moving all the
00646         // ones that are still playing to the front.
00647         std::vector<LLMultiGesture*>::iterator new_end;
00648         new_end = std::partition(mPlaying.begin(),
00649                                                          mPlaying.end(),
00650                                                          IsGesturePlaying());
00651 
00652         // Something finished playing
00653         if (new_end != mPlaying.end())
00654         {
00655                 // Delete the completed gestures that want deletion
00656                 std::vector<LLMultiGesture*>::iterator it;
00657                 for (it = new_end; it != mPlaying.end(); ++it)
00658                 {
00659                         LLMultiGesture* gesture = *it;
00660 
00661                         if (gesture->mDoneCallback)
00662                         {
00663                                 gesture->mDoneCallback(gesture, gesture->mCallbackData);
00664 
00665                                 // callback might have deleted gesture, can't
00666                                 // rely on this pointer any more
00667                                 gesture = NULL;
00668                         }
00669                 }
00670 
00671                 // And take done gestures out of the playing list
00672                 mPlaying.erase(new_end, mPlaying.end());
00673 
00674                 notifyObservers();
00675         }
00676 }
00677 
00678 
00679 // Run all steps until you're either done or hit a wait.
00680 void LLGestureManager::stepGesture(LLMultiGesture* gesture)
00681 {
00682         if (!gesture)
00683         {
00684                 return;
00685         }
00686         LLVOAvatar* avatar = gAgent.getAvatarObject();
00687         if (!avatar) return;
00688 
00689         // Of the ones that started playing, have any stopped?
00690 
00691         std::set<LLUUID>::iterator gest_it;
00692         for (gest_it = gesture->mPlayingAnimIDs.begin(); 
00693                  gest_it != gesture->mPlayingAnimIDs.end(); 
00694                  )
00695         {
00696                 // look in signaled animations (simulator's view of what is
00697                 // currently playing.
00698                 LLVOAvatar::AnimIterator play_it = avatar->mSignaledAnimations.find(*gest_it);
00699                 if (play_it != avatar->mSignaledAnimations.end())
00700                 {
00701                         ++gest_it;
00702                 }
00703                 else
00704                 {
00705                         // not found, so not currently playing or scheduled to play
00706                         // delete from the triggered set
00707                         gesture->mPlayingAnimIDs.erase(gest_it++);
00708                 }
00709         }
00710 
00711         // Of all the animations that we asked the sim to start for us,
00712         // pick up the ones that have actually started.
00713         for (gest_it = gesture->mRequestedAnimIDs.begin();
00714                  gest_it != gesture->mRequestedAnimIDs.end();
00715                  )
00716         {
00717          LLVOAvatar::AnimIterator play_it = avatar->mSignaledAnimations.find(*gest_it);
00718                 if (play_it != avatar->mSignaledAnimations.end())
00719                 {
00720                         // Hooray, this animation has started playing!
00721                         // Copy into playing.
00722                         gesture->mPlayingAnimIDs.insert(*gest_it);
00723                         gesture->mRequestedAnimIDs.erase(gest_it++);
00724                 }
00725                 else
00726                 {
00727                         // nope, not playing yet
00728                         ++gest_it;
00729                 }
00730         }
00731 
00732         // Run the current steps
00733         BOOL waiting = FALSE;
00734         while (!waiting && gesture->mPlaying)
00735         {
00736                 // Get the current step, if there is one.
00737                 // Otherwise enter the waiting at end state.
00738                 LLGestureStep* step = NULL;
00739                 if (gesture->mCurrentStep < (S32)gesture->mSteps.size())
00740                 {
00741                         step = gesture->mSteps[gesture->mCurrentStep];
00742                         llassert(step != NULL);
00743                 }
00744                 else
00745                 {
00746                         // step stays null, we're off the end
00747                         gesture->mWaitingAtEnd = TRUE;
00748                 }
00749 
00750 
00751                 // If we're waiting at the end, wait for all gestures to stop
00752                 // playing.
00753                 // TODO: Wait for all sounds to complete as well.
00754                 if (gesture->mWaitingAtEnd)
00755                 {
00756                         // Neither do we have any pending requests, nor are they
00757                         // still playing.
00758                         if ((gesture->mRequestedAnimIDs.empty()
00759                                 && gesture->mPlayingAnimIDs.empty()))
00760                         {
00761                                 // all animations are done playing
00762                                 gesture->mWaitingAtEnd = FALSE;
00763                                 gesture->mPlaying = FALSE;
00764                         }
00765                         else
00766                         {
00767                                 waiting = TRUE;
00768                         }
00769                         continue;
00770                 }
00771 
00772                 // If we're waiting on our animations to stop, poll for
00773                 // completion.
00774                 if (gesture->mWaitingAnimations)
00775                 {
00776                         // Neither do we have any pending requests, nor are they
00777                         // still playing.
00778                         if ((gesture->mRequestedAnimIDs.empty()
00779                                 && gesture->mPlayingAnimIDs.empty()))
00780                         {
00781                                 // all animations are done playing
00782                                 gesture->mWaitingAnimations = FALSE;
00783                                 gesture->mCurrentStep++;
00784                         }
00785                         else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS)
00786                         {
00787                                 // we've waited too long for an animation
00788                                 llinfos << "Waited too long for animations to stop, continuing gesture."
00789                                         << llendl;
00790                                 gesture->mWaitingAnimations = FALSE;
00791                                 gesture->mCurrentStep++;
00792                         }
00793                         else
00794                         {
00795                                 waiting = TRUE;
00796                         }
00797                         continue;
00798                 }
00799 
00800                 // If we're waiting a fixed amount of time, check for timer
00801                 // expiration.
00802                 if (gesture->mWaitingTimer)
00803                 {
00804                         // We're waiting for a certain amount of time to pass
00805                         LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
00806 
00807                         F32 elapsed = gesture->mWaitTimer.getElapsedTimeF32();
00808                         if (elapsed > wait_step->mWaitSeconds)
00809                         {
00810                                 // wait is done, continue execution
00811                                 gesture->mWaitingTimer = FALSE;
00812                                 gesture->mCurrentStep++;
00813                         }
00814                         else
00815                         {
00816                                 // we're waiting, so execution is done for now
00817                                 waiting = TRUE;
00818                         }
00819                         continue;
00820                 }
00821 
00822                 // Not waiting, do normal execution
00823                 runStep(gesture, step);
00824         }
00825 }
00826 
00827 
00828 void LLGestureManager::runStep(LLMultiGesture* gesture, LLGestureStep* step)
00829 {
00830         switch(step->getType())
00831         {
00832         case STEP_ANIMATION:
00833                 {
00834                         LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
00835                         if (anim_step->mAnimAssetID.isNull())
00836                         {
00837                                 gesture->mCurrentStep++;
00838                         }
00839 
00840                         if (anim_step->mFlags & ANIM_FLAG_STOP)
00841                         {
00842                                 gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_STOP);
00843                                 // remove it from our request set in case we just requested it
00844                                 std::set<LLUUID>::iterator set_it = gesture->mRequestedAnimIDs.find(anim_step->mAnimAssetID);
00845                                 if (set_it != gesture->mRequestedAnimIDs.end())
00846                                 {
00847                                         gesture->mRequestedAnimIDs.erase(set_it);
00848                                 }
00849                         }
00850                         else
00851                         {
00852                                 gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_START);
00853                                 // Indicate that we've requested this animation to play as
00854                                 // part of this gesture (but it won't start playing for at
00855                                 // least one round-trip to simulator).
00856                                 gesture->mRequestedAnimIDs.insert(anim_step->mAnimAssetID);
00857                         }
00858                         gesture->mCurrentStep++;
00859                         break;
00860                 }
00861         case STEP_SOUND:
00862                 {
00863                         LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
00864                         const LLUUID& sound_id = sound_step->mSoundAssetID;
00865                         const F32 volume = 1.f;
00866                         send_sound_trigger(sound_id, volume);
00867                         gesture->mCurrentStep++;
00868                         break;
00869                 }
00870         case STEP_CHAT:
00871                 {
00872                         LLGestureStepChat* chat_step = (LLGestureStepChat*)step;
00873                         std::string chat_text = chat_step->mChatText;
00874                         // Don't animate the nodding, as this might not blend with
00875                         // other playing animations.
00876                         const BOOL animate = FALSE;
00877 
00878                         gChatBar->sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate);
00879                         gesture->mCurrentStep++;
00880                         break;
00881                 }
00882         case STEP_WAIT:
00883                 {
00884                         LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
00885                         if (wait_step->mFlags & WAIT_FLAG_TIME)
00886                         {
00887                                 gesture->mWaitingTimer = TRUE;
00888                                 gesture->mWaitTimer.reset();
00889                         }
00890                         else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM)
00891                         {
00892                                 gesture->mWaitingAnimations = TRUE;
00893                                 // Use the wait timer as a deadlock breaker for animation
00894                                 // waits.
00895                                 gesture->mWaitTimer.reset();
00896                         }
00897                         else
00898                         {
00899                                 gesture->mCurrentStep++;
00900                         }
00901                         // Don't increment instruction pointer until wait is complete.
00902                         break;
00903                 }
00904         default:
00905                 {
00906                         break;
00907                 }
00908         }
00909 }
00910 
00911 
00912 // static
00913 void LLGestureManager::onLoadComplete(LLVFS *vfs,
00914                                                                            const LLUUID& asset_uuid,
00915                                                                            LLAssetType::EType type,
00916                                                                            void* user_data, S32 status, LLExtStat ext_status)
00917 {
00918         LLLoadInfo* info = (LLLoadInfo*)user_data;
00919 
00920         LLUUID item_id = info->mItemID;
00921         BOOL inform_server = info->mInformServer;
00922         BOOL deactivate_similar = info->mDeactivateSimilar;
00923 
00924         delete info;
00925         info = NULL;
00926 
00927         gGestureManager.mLoadingCount--;
00928 
00929         if (0 == status)
00930         {
00931                 LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
00932                 S32 size = file.getSize();
00933 
00934                 char* buffer = new char[size+1];
00935                 if (buffer == NULL)
00936                 {
00937                         llerrs << "Memory Allocation Failed" << llendl;
00938                         return;
00939                 }
00940 
00941                 file.read((U8*)buffer, size);           /* Flawfinder: ignore */
00942                 // ensure there's a trailing NULL so strlen will work.
00943                 buffer[size] = '\0';
00944 
00945                 LLMultiGesture* gesture = new LLMultiGesture();
00946 
00947                 LLDataPackerAsciiBuffer dp(buffer, size+1);
00948                 BOOL ok = gesture->deserialize(dp);
00949 
00950                 if (ok)
00951                 {
00952                         if (deactivate_similar)
00953                         {
00954                                 gGestureManager.deactivateSimilarGestures(gesture, item_id);
00955 
00956                                 // Display deactivation message if this was the last of the bunch.
00957                                 if (gGestureManager.mLoadingCount == 0
00958                                         && gGestureManager.mDeactivateSimilarNames.length() > 0)
00959                                 {
00960                                         // we're done with this set of deactivations
00961                                         LLString::format_map_t args;
00962                                         args["[NAMES]"] = gGestureManager.mDeactivateSimilarNames;
00963                                         LLNotifyBox::showXml("DeactivatedGesturesTrigger", args);
00964                                 }
00965                         }
00966 
00967                         // Everything has been successful.  Add to the active list.
00968                         gGestureManager.mActive[item_id] = gesture;
00969                         gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
00970                         if (inform_server)
00971                         {
00972                                 // Inform the database of this change
00973                                 LLMessageSystem* msg = gMessageSystem;
00974                                 msg->newMessage("ActivateGestures");
00975                                 msg->nextBlock("AgentData");
00976                                 msg->addUUID("AgentID", gAgent.getID());
00977                                 msg->addUUID("SessionID", gAgent.getSessionID());
00978                                 msg->addU32("Flags", 0x0);
00979                                 
00980                                 msg->nextBlock("Data");
00981                                 msg->addUUID("ItemID", item_id);
00982                                 msg->addUUID("AssetID", asset_uuid);
00983                                 msg->addU32("GestureFlags", 0x0);
00984 
00985                                 gAgent.sendReliableMessage();
00986                         }
00987 
00988                         gGestureManager.notifyObservers();
00989                 }
00990                 else
00991                 {
00992                         llwarns << "Unable to load gesture" << llendl;
00993 
00994                         gGestureManager.mActive.erase(item_id);
00995                         
00996                         delete gesture;
00997                         gesture = NULL;
00998                 }
00999 
01000                 delete [] buffer;
01001                 buffer = NULL;
01002         }
01003         else
01004         {
01005                 if( gViewerStats )
01006                 {
01007                         gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
01008                 }
01009 
01010                 if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
01011                         LL_ERR_FILE_EMPTY == status)
01012                 {
01013                         LLNotifyBox::showXml("GestureMissing");
01014                 }
01015                 else
01016                 {
01017                         LLNotifyBox::showXml("UnableToLoadGesture");
01018                 }
01019 
01020                 llwarns << "Problem loading gesture: " << status << llendl;
01021                 
01022                 gGestureManager.mActive.erase(item_id);                 
01023         }
01024 }
01025 
01026 
01027 void LLGestureManager::stopGesture(LLMultiGesture* gesture)
01028 {
01029         if (!gesture) return;
01030 
01031         // Stop any animations that this gesture is currently playing
01032         std::set<LLUUID>::const_iterator set_it;
01033         for (set_it = gesture->mRequestedAnimIDs.begin(); set_it != gesture->mRequestedAnimIDs.end(); ++set_it)
01034         {
01035                 const LLUUID& anim_id = *set_it;
01036                 gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP);
01037         }
01038         for (set_it = gesture->mPlayingAnimIDs.begin(); set_it != gesture->mPlayingAnimIDs.end(); ++set_it)
01039         {
01040                 const LLUUID& anim_id = *set_it;
01041                 gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP);
01042         }
01043 
01044         std::vector<LLMultiGesture*>::iterator it;
01045         it = std::find(mPlaying.begin(), mPlaying.end(), gesture);
01046         while (it != mPlaying.end())
01047         {
01048                 mPlaying.erase(it);
01049                 it = std::find(mPlaying.begin(), mPlaying.end(), gesture);
01050         }
01051 
01052         gesture->reset();
01053 
01054         if (gesture->mDoneCallback)
01055         {
01056                 gesture->mDoneCallback(gesture, gesture->mCallbackData);
01057 
01058                 // callback might have deleted gesture, can't
01059                 // rely on this pointer any more
01060                 gesture = NULL;
01061         }
01062 
01063         notifyObservers();
01064 }
01065 
01066 
01067 void LLGestureManager::stopGesture(const LLUUID& item_id)
01068 {
01069         item_map_t::iterator it = mActive.find(item_id);
01070         if (it == mActive.end()) return;
01071 
01072         LLMultiGesture* gesture = (*it).second;
01073         if (!gesture) return;
01074 
01075         stopGesture(gesture);
01076 }
01077 
01078 
01079 void LLGestureManager::addObserver(LLGestureManagerObserver* observer)
01080 {
01081         mObservers.push_back(observer);
01082 }
01083 
01084 void LLGestureManager::removeObserver(LLGestureManagerObserver* observer)
01085 {
01086         std::vector<LLGestureManagerObserver*>::iterator it;
01087         it = std::find(mObservers.begin(), mObservers.end(), observer);
01088         if (it != mObservers.end())
01089         {
01090                 mObservers.erase(it);
01091         }
01092 }
01093 
01094 // Call this method when it's time to update everyone on a new state.
01095 // Copy the list because an observer could respond by removing itself
01096 // from the list.
01097 void LLGestureManager::notifyObservers()
01098 {
01099         lldebugs << "LLGestureManager::notifyObservers" << llendl;
01100 
01101         std::vector<LLGestureManagerObserver*> observers = mObservers;
01102 
01103         std::vector<LLGestureManagerObserver*>::iterator it;
01104         for (it = observers.begin(); it != observers.end(); ++it)
01105         {
01106                 LLGestureManagerObserver* observer = *it;
01107                 observer->changed();
01108         }
01109 }
01110 
01111 BOOL LLGestureManager::matchPrefix(const std::string& in_str, std::string* out_str)
01112 {
01113         S32 in_len = in_str.length();
01114 
01115         item_map_t::iterator it;
01116         for (it = mActive.begin(); it != mActive.end(); ++it)
01117         {
01118                 LLMultiGesture* gesture = (*it).second;
01119                 if (gesture)
01120                 {
01121                         const std::string& trigger = gesture->getTrigger();
01122                         
01123                         if (in_len > (S32)trigger.length())
01124                         {
01125                                 // too short, bail out
01126                                 continue;
01127                         }
01128 
01129                         LLString trigger_trunc = trigger;
01130                         LLString::truncate(trigger_trunc, in_len);
01131                         if (!LLString::compareInsensitive(in_str.c_str(), trigger_trunc.c_str()))
01132                         {
01133                                 *out_str = trigger;
01134                                 return TRUE;
01135                         }
01136                 }
01137         }
01138         return FALSE;
01139 }
01140 
01141 
01142 void LLGestureManager::getItemIDs(std::vector<LLUUID>* ids)
01143 {
01144         item_map_t::const_iterator it;
01145         for (it = mActive.begin(); it != mActive.end(); ++it)
01146         {
01147                 ids->push_back(it->first);
01148         }
01149 }

Generated on Thu Jul 1 06:08:39 2010 for Second Life Viewer by  doxygen 1.4.7