diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/rlvhelper.cpp | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/linden/indra/newview/rlvhelper.cpp b/linden/indra/newview/rlvhelper.cpp new file mode 100644 index 0000000..6b2a1a0 --- /dev/null +++ b/linden/indra/newview/rlvhelper.cpp | |||
@@ -0,0 +1,674 @@ | |||
1 | #include "llviewerprecompiledheaders.h" | ||
2 | #include "llagent.h" | ||
3 | #include "llviewerobject.h" | ||
4 | #include "llviewerstats.h" | ||
5 | #include "llviewerwindow.h" | ||
6 | #include "llvoavatar.h" | ||
7 | #include "llwlparammanager.h" | ||
8 | |||
9 | #include "rlvhelper.h" | ||
10 | #include "rlvevent.h" | ||
11 | #include "rlvhandler.h" | ||
12 | |||
13 | // ============================================================================ | ||
14 | // Static variable initialization | ||
15 | // | ||
16 | |||
17 | RlvMultiStringSearch RlvCommand::m_BhvrLookup; | ||
18 | |||
19 | // ============================================================================ | ||
20 | |||
21 | // Checked: | ||
22 | RlvCommand::RlvCommand(const std::string& strCommand) | ||
23 | : m_eBehaviour(RLV_BHVR_UNKNOWN), m_eParamType(RLV_TYPE_UNKNOWN) | ||
24 | { | ||
25 | if ((m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam))) | ||
26 | { | ||
27 | if ( ("n" == m_strParam) || ("add" == m_strParam) ) | ||
28 | m_eParamType = RLV_TYPE_ADD; | ||
29 | else if ( ("y" == m_strParam) || ("rem" == m_strParam) ) | ||
30 | m_eParamType = RLV_TYPE_REMOVE; | ||
31 | else if ("force" == m_strParam) | ||
32 | m_eParamType = RLV_TYPE_FORCE; | ||
33 | else | ||
34 | { | ||
35 | m_eParamType = RLV_TYPE_REPLY; // Assume it's a reply command until we encounter a non-digit | ||
36 | |||
37 | if ( (m_strParam.empty()) || (-1 != m_strParam.find_first_not_of("0123456789")) ) | ||
38 | { | ||
39 | m_eParamType = RLV_TYPE_UNKNOWN; | ||
40 | m_fValid = ("clear" == m_strBehaviour); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | if (!m_fValid) | ||
46 | { | ||
47 | m_strBehaviour = m_strOption = m_strParam = ""; | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | U16 nBehaviour; | ||
52 | if (m_BhvrLookup.getExactMatchParam(m_strBehaviour, nBehaviour)) | ||
53 | { | ||
54 | m_eBehaviour = (ERlvBehaviour)nBehaviour; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | RlvCommand::RlvCommand(const RlvCommand& rlvCmd) | ||
59 | : m_fValid(rlvCmd.m_fValid), | ||
60 | m_strBehaviour(rlvCmd.m_strBehaviour), m_eBehaviour(rlvCmd.m_eBehaviour), | ||
61 | m_strOption(rlvCmd.m_strOption), | ||
62 | m_strParam(rlvCmd.m_strParam), m_eParamType(rlvCmd.m_eParamType) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | // ============================================================================ | ||
67 | |||
68 | /* | ||
69 | * ------------------------------ | ||
70 | * Command | RLV | RLVa | ||
71 | * ------------------------------ | ||
72 | * : | F | F (missing behaviour) | ||
73 | * :option | F | F (missing behaviour) | ||
74 | * := | T | F (missing behaviour) | ||
75 | * :option= | T | F (missing behaviour) | ||
76 | * :option=param | T | F (missing behaviour) | ||
77 | * = | T | F (missing behaviour) | ||
78 | * =param | T | F (missing behaviour) | ||
79 | * cmd | F | F (missing param) [T if <behaviour> == "clear"] | ||
80 | * cmd: | F | F (missing param) | ||
81 | * cmd:option | F | F (missing param) | ||
82 | * cmd:= | T | F (missing param) [1] | ||
83 | * cmd:option= | T | F (missing param) [1] | ||
84 | * cmd= | T | F (missing param) [1] | ||
85 | * cmd:option=param | T | T | ||
86 | * cmd=param | T | T | ||
87 | * cmd:=param | T | T | ||
88 | * | ||
89 | * [1] 'clear:=', 'clear:option=' and 'clear=' are "valid" variations of 'clear' | ||
90 | */ | ||
91 | |||
92 | BOOL RlvCommand::parseCommand(/*[in]*/ const std::string& strCommand, | ||
93 | /*[out]*/ std::string& strBehaviour, /*[out]*/ std::string& strOption, /*[out]*/ std::string& strParam) | ||
94 | { | ||
95 | // Format: <behaviour>[:<option>]=<param> | ||
96 | int idxParam = strCommand.find('='); | ||
97 | int idxOption = (idxParam > 0) ? strCommand.find(':') : -1; | ||
98 | if (idxOption > idxParam - 1) | ||
99 | idxOption = -1; | ||
100 | |||
101 | // If <behaviour> is missing it's always an improperly formatted command | ||
102 | if ( (0 == idxOption) || (0 == idxParam) ) | ||
103 | return FALSE; | ||
104 | |||
105 | strBehaviour = strCommand.substr(0, (-1 != idxOption) ? idxOption : idxParam); | ||
106 | strOption = strParam = ""; | ||
107 | |||
108 | // If <param> is missing it's an improperly formatted command | ||
109 | if ( (-1 == idxParam) || ((int)strCommand.length() - 1 == idxParam) ) | ||
110 | { | ||
111 | // Unless "<behaviour> == "clear" AND (idxOption == 0)" | ||
112 | // OR <behaviour> == "clear" AND (idxParam != 0) [see table above] | ||
113 | if ( ("clear" == strBehaviour) && ( (!idxOption) || (idxParam) ) ) | ||
114 | return TRUE; | ||
115 | return FALSE; | ||
116 | } | ||
117 | |||
118 | if ( (-1 != idxOption) && (idxOption + 1 != idxParam) ) | ||
119 | strOption = strCommand.substr(idxOption + 1, idxParam - idxOption - 1); | ||
120 | strParam = strCommand.substr(idxParam + 1); | ||
121 | |||
122 | return TRUE; | ||
123 | } | ||
124 | |||
125 | void RlvCommand::initLookupTable() | ||
126 | { | ||
127 | static bool fInitialized = false; | ||
128 | if (!fInitialized) | ||
129 | { | ||
130 | // NOTE: keep this match with the enumeration at all times | ||
131 | std::string arBehaviours[RLV_BHVR_COUNT] = | ||
132 | { | ||
133 | "version", "detach", "redirchat", "rediremote", "sendim", "recvchat", "recvemote", "recvim", "tploc", "tplure", | ||
134 | "sittp", "edit", "rez", "addoutfit", "remoutfit", "getoutfit", "getattach", "showinv", "unsit", "sit", | ||
135 | "getstatus", "getstatusall", "getinv", "getinvworn", "findfolder", "findfolders", "attach", "attachall", "detachall", | ||
136 | "getpath", "attachthis", "attachallthis", "detachthis", "detachallthis", "fartouch", "showworldmap", "showminimap", | ||
137 | "showloc", "tpto", "accepttp", "shownames", "fly", "getsitid", "setdebug", "setenv", "detachme", | ||
138 | "showhovertextall", "showhovertextworld", "showhovertexthud", "showhovertext", "notify" | ||
139 | }; | ||
140 | |||
141 | for (int idxBvhr = 0; idxBvhr < RLV_BHVR_COUNT; idxBvhr++) | ||
142 | m_BhvrLookup.addKeyword(arBehaviours[idxBvhr], idxBvhr); | ||
143 | |||
144 | fInitialized = true; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | // Checked: 2009-06-07 (RLVa-0.2.1c) | ||
149 | std::string RlvCommand::asString() const | ||
150 | { | ||
151 | return (!m_strOption.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strOption) : (std::string(m_strBehaviour)); | ||
152 | } | ||
153 | |||
154 | // ========================================================================= | ||
155 | |||
156 | BOOL RlvObject::addCommand(const RlvCommand& rlvCmd) | ||
157 | { | ||
158 | // Sanity checking | ||
159 | if (RLV_TYPE_ADD != rlvCmd.getParamType()) | ||
160 | return FALSE; | ||
161 | |||
162 | // Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on) | ||
163 | BOOL fDuplicate = | ||
164 | (RLV_BHVR_UNKNOWN != rlvCmd.getBehaviourType()) | ||
165 | ? hasBehaviour(rlvCmd.getBehaviourType(), rlvCmd.getOption()) | ||
166 | : hasBehaviour(rlvCmd.getBehaviour(), rlvCmd.getOption()); | ||
167 | if (fDuplicate) | ||
168 | return FALSE; | ||
169 | |||
170 | // Now that we know it's not a duplicate, add it to the end of the list | ||
171 | m_Commands.push_back(rlvCmd); | ||
172 | |||
173 | return TRUE; | ||
174 | } | ||
175 | |||
176 | BOOL RlvObject::removeCommand(const RlvCommand& rlvCmd) | ||
177 | { | ||
178 | // Sanity checking | ||
179 | if (RLV_TYPE_REMOVE != rlvCmd.getParamType()) | ||
180 | return FALSE; | ||
181 | |||
182 | for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) | ||
183 | { | ||
184 | //if (*itCmd == rlvCmd) <- commands will never be equal since one is an add and the other is a remove *rolls eyes* | ||
185 | if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) ) | ||
186 | { | ||
187 | m_Commands.erase(itCmd); | ||
188 | return TRUE; | ||
189 | } | ||
190 | } | ||
191 | return FALSE; // Command was never added so nothing to remove now | ||
192 | } | ||
193 | |||
194 | BOOL RlvObject::hasBehaviour(ERlvBehaviour eBehaviour) const | ||
195 | { | ||
196 | for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) | ||
197 | if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption().empty()) ) | ||
198 | return TRUE; | ||
199 | return FALSE; | ||
200 | } | ||
201 | |||
202 | BOOL RlvObject::hasBehaviour(const std::string& strBehaviour) const | ||
203 | { | ||
204 | for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) | ||
205 | if ( (itCmd->getBehaviour() == strBehaviour) && (itCmd->getOption().empty()) ) | ||
206 | return TRUE; | ||
207 | return FALSE; | ||
208 | } | ||
209 | |||
210 | BOOL RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const | ||
211 | { | ||
212 | for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) | ||
213 | if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption() == strOption) ) | ||
214 | return TRUE; | ||
215 | return FALSE; | ||
216 | } | ||
217 | |||
218 | BOOL RlvObject::hasBehaviour(const std::string& strBehaviour, const std::string& strOption) const | ||
219 | { | ||
220 | for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) | ||
221 | if ( (itCmd->getBehaviour() == strBehaviour) && (itCmd->getOption() == strOption) ) | ||
222 | return TRUE; | ||
223 | return FALSE; | ||
224 | } | ||
225 | |||
226 | // Checked: 2009-06-07 (RLVa-0.2.1c) | ||
227 | std::string RlvObject::getStatusString(const std::string& strMatch) const | ||
228 | { | ||
229 | std::string strStatus, strCmd; | ||
230 | |||
231 | for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) | ||
232 | { | ||
233 | strCmd = itCmd->asString(); | ||
234 | if ( (strMatch.empty()) || (std::string::npos != strCmd.find(strMatch)) ) | ||
235 | { | ||
236 | if (!strStatus.empty()) | ||
237 | strStatus.push_back('/'); | ||
238 | strStatus += strCmd; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | return strStatus; | ||
243 | } | ||
244 | |||
245 | // ========================================================================= | ||
246 | /* | ||
247 | * Various helper classes/timers/functors | ||
248 | * | ||
249 | */ | ||
250 | |||
251 | // Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d | ||
252 | S32 rlvGetDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType type) | ||
253 | { | ||
254 | S32 cntType = 0; | ||
255 | if (pFolder) | ||
256 | { | ||
257 | LLInventoryModel::cat_array_t* pFolders; | ||
258 | LLInventoryModel::item_array_t* pItems; | ||
259 | gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); | ||
260 | |||
261 | if (pItems) | ||
262 | { | ||
263 | for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++) | ||
264 | if (pItems->get(idxItem)->getType() == type) | ||
265 | cntType++; | ||
266 | } | ||
267 | } | ||
268 | return cntType; | ||
269 | } | ||
270 | |||
271 | // Checked: 2009-05-30 (RLVa-0.2.0e) | Added: RLVa-0.2.0e | ||
272 | const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) const | ||
273 | { | ||
274 | std::map<LLUUID, LLUUID>::const_iterator itFolder = m_Folding.end(), itCur = m_Folding.find(idFolder); | ||
275 | while (itCur != m_Folding.end()) | ||
276 | { | ||
277 | itFolder = itCur; | ||
278 | itCur = m_Folding.find(itFolder->second); | ||
279 | } | ||
280 | return (m_Folding.end() == itFolder) ? idFolder : itFolder->second; | ||
281 | } | ||
282 | |||
283 | // Checked: 2009-07-29 (RLVa-1.0.1b) | Modified: RLVa-1.0.1b | ||
284 | bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder) | ||
285 | { | ||
286 | const LLUUID& idParent = pFolder->getParentUUID(); | ||
287 | if (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) | ||
288 | return false; // Not the child of a wearable folder == skip | ||
289 | |||
290 | const std::string& strFolder = pFolder->getName(); | ||
291 | if (strFolder.empty()) // Shouldn't happen but does... naughty Lindens | ||
292 | return false; | ||
293 | |||
294 | #ifdef RLV_EXTENSION_FLAG_NOSTRIP | ||
295 | if ( (!m_fAttach) && (-1 != strFolder.find(RLV_FOLDER_FLAG_NOSTRIP)) ) // Don't process "nostrip" folders on detach | ||
296 | return false; | ||
297 | #endif // RLV_EXTENSION_FLAG_NOSTRIP | ||
298 | |||
299 | if (gRlvHandler.isFoldedFolder(pFolder, m_fAttach)) // Check for folder that should get folded under its parent | ||
300 | { | ||
301 | m_Tentative.push_front(pFolder->getUUID()); | ||
302 | m_Folding.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent)); | ||
303 | } | ||
304 | else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && (m_fMatchAll) ) // Collect from any non-hidden child folder for *all | ||
305 | { | ||
306 | m_Wearable.push_front(pFolder->getUUID()); | ||
307 | return (idParent == m_idFolder); // (Convenience for @getinvworn) | ||
308 | } | ||
309 | #ifdef RLV_EXPERIMENTAL_COMPOSITES | ||
310 | else if ( (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) && // Hidden folder that's a... | ||
311 | (gRlvHandler.isCompositeFolder(pFolder)) && // ... composite folder which we... | ||
312 | ((m_fAttach) || (gRlvHandler.canTakeOffComposite(pFolder))) ) // ... attach or can detach (see composite locking) | ||
313 | { | ||
314 | m_Wearable.push_front(pFolder->getUUID()); | ||
315 | m_Folding.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent)); | ||
316 | } | ||
317 | #endif // RLV_EXPERIMENTAL_COMPOSITES | ||
318 | |||
319 | return false; | ||
320 | } | ||
321 | |||
322 | // Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d | ||
323 | bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem) | ||
324 | { | ||
325 | #ifdef RLV_EXTENSION_FLAG_NOSTRIP | ||
326 | if ( (!m_fAttach) && (-1 != pItem->getName().find(RLV_FOLDER_FLAG_NOSTRIP)) ) // Don't process "nostrip" items on detach | ||
327 | return false; | ||
328 | #endif // RLV_EXTENSION_FLAG_NOSTRIP | ||
329 | |||
330 | const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false; | ||
331 | switch (pItem->getType()) | ||
332 | { | ||
333 | case LLAssetType::AT_BODYPART: | ||
334 | if (!m_fAttach) | ||
335 | break; // Don't process body parts on detach | ||
336 | case LLAssetType::AT_CLOTHING: | ||
337 | #ifdef RLV_EXTENSION_FLAG_NOSTRIP | ||
338 | fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || | ||
339 | ( (m_fAttach) && (m_Tentative.end() != std::find(m_Tentative.begin(), m_Tentative.end(), idParent)) && | ||
340 | (gInventory.getCategory(pItem->getParentUUID())->getName() == ".("RLV_FOLDER_FLAG_NOSTRIP")") ) ); | ||
341 | #else | ||
342 | fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); | ||
343 | #endif // RLV_EXTENSION_FLAG_NOSTRIP | ||
344 | break; | ||
345 | case LLAssetType::AT_OBJECT: | ||
346 | fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || | ||
347 | (m_Tentative.end() != std::find(m_Tentative.begin(), m_Tentative.end(), idParent)) ) && | ||
348 | ( (!m_fAttach) || (gRlvHandler.hasAttachPointName(pItem, true)) ); // Only care about attach point on attach* | ||
349 | break; | ||
350 | #ifdef RLV_EXPERIMENTAL_FORCEWEAR_GESTURES | ||
351 | case LLAssetType::AT_GESTURE: | ||
352 | fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); | ||
353 | break; | ||
354 | #endif // RLV_EXPERIMENTAL_FORCEWEAR_GESTURES | ||
355 | default: | ||
356 | break; | ||
357 | } | ||
358 | return fRet; | ||
359 | } | ||
360 | |||
361 | // Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d | ||
362 | bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) | ||
363 | { | ||
364 | // NOTE: this is used for more than was originally intended so only modify if you're sure it won't break something obscure | ||
365 | return (pFolder) ? onCollectFolder(pFolder) : ( (pItem) ? onCollectItem(pItem) : false ); | ||
366 | } | ||
367 | |||
368 | // Checked: 2009-07-06 (RLVa-1.0.0c) | Modified: RLVa-0.2.0f | ||
369 | bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode) | ||
370 | { | ||
371 | return (pNode->getObject()) ? !gRlvHandler.isDetachable(pNode->getObject()) : false; | ||
372 | } | ||
373 | |||
374 | // Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0f | ||
375 | bool RlvSelectIsOwnedByOrGroupOwned::apply(LLSelectNode* pNode) | ||
376 | { | ||
377 | return (pNode->mPermissions->isGroupOwned()) || (pNode->mPermissions->getOwner() == m_idAgent); | ||
378 | } | ||
379 | |||
380 | // Checked: 2009-05-31 (RLVa-0.2.0f) | Modified: RLVa-0.2.0f | ||
381 | bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode) | ||
382 | { | ||
383 | return (pNode->getObject()) && (pNode->getObject()->getRootEdit() == m_pObject); | ||
384 | } | ||
385 | |||
386 | // Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0g | ||
387 | bool rlvCanDeleteOrReturn() | ||
388 | { | ||
389 | bool fIsAllowed = true; | ||
390 | |||
391 | if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) | ||
392 | { | ||
393 | // We'll allow if none of the prims are owned by the avie or group owned | ||
394 | LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); | ||
395 | RlvSelectIsOwnedByOrGroupOwned func(gAgent.getID()); | ||
396 | if ( (handleSel.notNull()) && ((0 == handleSel->getRootObjectCount()) || (NULL != handleSel->getFirstRootNode(&func, FALSE))) ) | ||
397 | fIsAllowed = false; | ||
398 | } | ||
399 | |||
400 | if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (gAgent.getAvatarObject()) ) | ||
401 | { | ||
402 | // We'll allow if the avie isn't sitting on any of the selected objects | ||
403 | LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection(); | ||
404 | RlvSelectIsSittingOn func(gAgent.getAvatarObject()->getRoot()); | ||
405 | if ( (handleSel.notNull()) && (handleSel->getFirstRootNode(&func, TRUE)) ) | ||
406 | fIsAllowed = false; | ||
407 | } | ||
408 | |||
409 | return fIsAllowed; | ||
410 | } | ||
411 | |||
412 | // Checked: 2009-07-05 (RLVa-1.0.0c) | ||
413 | BOOL rlvAttachToEnabler(void* pParam) | ||
414 | { | ||
415 | // Enables/disables an option on the "Attach to (HUD)" submenu depending on whether it is (un)detachable | ||
416 | LLViewerJointAttachment* pAttachment = (LLViewerJointAttachment*)pParam; | ||
417 | return (!pAttachment) || (gRlvHandler.isDetachable(pAttachment->getObject())); | ||
418 | } | ||
419 | |||
420 | BOOL RlvGCTimer::tick() | ||
421 | { | ||
422 | bool fContinue = gRlvHandler.onGC(); | ||
423 | if (!fContinue) | ||
424 | gRlvHandler.m_pGCTimer = NULL; | ||
425 | return !fContinue; | ||
426 | } | ||
427 | |||
428 | void RlvCurrentlyWorn::fetchWorn() | ||
429 | { | ||
430 | LLInventoryFetchObserver::item_ref_t idItems; | ||
431 | |||
432 | // Fetch all currently worn clothing layers and body parts | ||
433 | for (int type = 0; type < (int)WT_COUNT; type++) | ||
434 | { | ||
435 | const LLUUID& idItem = gAgent.getWearableItem((EWearableType)type); | ||
436 | if (idItem.notNull()) | ||
437 | idItems.push_back(idItem); | ||
438 | } | ||
439 | |||
440 | // Fetch all currently worn attachments | ||
441 | LLVOAvatar* pAvatar = gAgent.getAvatarObject(); | ||
442 | if (pAvatar) | ||
443 | { | ||
444 | for (LLVOAvatar::attachment_map_t::const_iterator itAttach = pAvatar->mAttachmentPoints.begin(); | ||
445 | itAttach != pAvatar->mAttachmentPoints.end(); ++itAttach) | ||
446 | { | ||
447 | const LLUUID& idItem = itAttach->second->getItemID(); | ||
448 | if (idItem.notNull()) | ||
449 | idItems.push_back(idItem); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | RlvCurrentlyWorn f; | ||
454 | f.fetchItems(idItems); | ||
455 | } | ||
456 | |||
457 | // ========================================================================= | ||
458 | |||
459 | // Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h | ||
460 | void RlvWLSnapshot::restoreSnapshot(const RlvWLSnapshot* pWLSnapshot) | ||
461 | { | ||
462 | LLWLParamManager* pWLParams = LLWLParamManager::instance(); | ||
463 | if ( (pWLSnapshot) && (pWLParams) ) | ||
464 | { | ||
465 | pWLParams->mAnimator.mIsRunning = pWLSnapshot->fIsRunning; | ||
466 | pWLParams->mAnimator.mUseLindenTime = pWLSnapshot->fUseLindenTime; | ||
467 | pWLParams->mCurParams = pWLSnapshot->WLParams; | ||
468 | pWLParams->propagateParameters(); | ||
469 | } | ||
470 | } | ||
471 | |||
472 | // Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h | ||
473 | RlvWLSnapshot* RlvWLSnapshot::takeSnapshot() | ||
474 | { | ||
475 | RlvWLSnapshot* pWLSnapshot = NULL; | ||
476 | LLWLParamManager* pWLParams = LLWLParamManager::instance(); | ||
477 | if (pWLParams) | ||
478 | { | ||
479 | pWLSnapshot = new RlvWLSnapshot(); | ||
480 | pWLSnapshot->fIsRunning = pWLParams->mAnimator.mIsRunning; | ||
481 | pWLSnapshot->fUseLindenTime = pWLParams->mAnimator.mUseLindenTime; | ||
482 | pWLSnapshot->WLParams = pWLParams->mCurParams; | ||
483 | } | ||
484 | return pWLSnapshot; | ||
485 | } | ||
486 | |||
487 | // ========================================================================= | ||
488 | |||
489 | BOOL RlvSettings::fShowNameTags = FALSE; | ||
490 | |||
491 | #ifdef RLV_EXTENSION_STARTLOCATION | ||
492 | // Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1d | ||
493 | void RlvSettings::updateLoginLastLocation() | ||
494 | { | ||
495 | if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) | ||
496 | { | ||
497 | BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || | ||
498 | ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && | ||
499 | (gAgent.getAvatarObject()) && (!gAgent.getAvatarObject()->mIsSitting) ); | ||
500 | if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) | ||
501 | { | ||
502 | gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); | ||
503 | gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); | ||
504 | } | ||
505 | } | ||
506 | } | ||
507 | #endif // RLV_EXTENSION_STARTLOCATION | ||
508 | |||
509 | // ========================================================================= | ||
510 | |||
511 | #ifdef RLV_ADVANCED_TOGGLE_RLVA | ||
512 | // Checked: 2009-07-12 (RLVa-1.0.0h) | Modified: RLVa-1.0.0h | ||
513 | void rlvDbgToggleEnabled(void*) | ||
514 | { | ||
515 | gSavedSettings.setBOOL(RLV_SETTING_MAIN, !rlv_handler_t::isEnabled()); | ||
516 | |||
517 | #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11 | ||
518 | LLStringUtil::format_map_t args; | ||
519 | args["[MESSAGE]"] = llformat("Restrained Life Support will be %s after you restart", | ||
520 | (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" ); | ||
521 | gViewerWindow->alertXml("GenericAlert", args); | ||
522 | #else // Version: 1.23.4 | ||
523 | LLSD args; | ||
524 | args["MESSAGE"] = llformat("Restrained Life Support will be %s after you restart", | ||
525 | (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" ); | ||
526 | LLNotifications::instance().add("GenericAlert", args); | ||
527 | #endif | ||
528 | } | ||
529 | // Checked: 2009-07-08 (RLVa-1.0.0e) | ||
530 | BOOL rlvDbgGetEnabled(void*) | ||
531 | { | ||
532 | return rlv_handler_t::isEnabled(); | ||
533 | } | ||
534 | #endif // RLV_ADVANCED_TOGGLE_RLVA | ||
535 | |||
536 | // ========================================================================= | ||
537 | // Message sending functions | ||
538 | // | ||
539 | |||
540 | // Checked: 2009-08-11 (RLVa-1.0.1h) | Added: RLVa-1.0.1h | ||
541 | void rlvForceDetach(LLViewerJointAttachment* pAttachPt) | ||
542 | { | ||
543 | // Copy/paste from handle_detach_from_avatar() | ||
544 | LLViewerObject* attached_object = pAttachPt->getObject(); | ||
545 | if (attached_object) | ||
546 | { | ||
547 | gMessageSystem->newMessage("ObjectDetach"); | ||
548 | gMessageSystem->nextBlockFast(_PREHASH_AgentData); | ||
549 | gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); | ||
550 | gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
551 | |||
552 | gMessageSystem->nextBlockFast(_PREHASH_ObjectData); | ||
553 | gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); | ||
554 | gMessageSystem->sendReliable( gAgent.getRegionHost() ); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | void rlvSendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession) | ||
559 | { | ||
560 | // (See process_improved_im) | ||
561 | std::string strFullName; | ||
562 | gAgent.buildFullname(strFullName); | ||
563 | |||
564 | pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName, | ||
565 | strMsg, IM_ONLINE, IM_BUSY_AUTO_RESPONSE, idSession); | ||
566 | gAgent.sendReliableMessage(); | ||
567 | } | ||
568 | |||
569 | // Checked: 2009-08-05 (RLVa-1.0.1e) | Modified: RLVa-1.0.1e | ||
570 | bool rlvSendChatReply(S32 nChannel, const std::string& strReply) | ||
571 | { | ||
572 | if (!rlvIsValidChannel(nChannel)) | ||
573 | return false; | ||
574 | |||
575 | // Copy/paste from send_chat_from_viewer() | ||
576 | LLMessageSystem* msg = gMessageSystem; | ||
577 | msg->newMessageFast(_PREHASH_ChatFromViewer); | ||
578 | msg->nextBlockFast(_PREHASH_AgentData); | ||
579 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
580 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
581 | msg->nextBlockFast(_PREHASH_ChatData); | ||
582 | msg->addStringFast(_PREHASH_Message, strReply); | ||
583 | msg->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT); | ||
584 | msg->addS32("Channel", nChannel); | ||
585 | gAgent.sendReliableMessage(); | ||
586 | LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); | ||
587 | |||
588 | return true; | ||
589 | } | ||
590 | |||
591 | // ========================================================================= | ||
592 | // String helper functions | ||
593 | // | ||
594 | |||
595 | // Checked: 2009-07-04 (RLVa-1.0.0a) | ||
596 | void rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo) | ||
597 | { | ||
598 | if (strFrom.empty()) | ||
599 | return; | ||
600 | |||
601 | size_t lenFrom = strFrom.length(); | ||
602 | size_t lenTo = strTo.length(); | ||
603 | |||
604 | std::string strTemp(strText); | ||
605 | LLStringUtil::toLower(strTemp); | ||
606 | LLStringUtil::toLower(strFrom); | ||
607 | |||
608 | std::string::size_type idxCur, idxStart = 0, idxOffset = 0; | ||
609 | while ( (idxCur = strTemp.find(strFrom, idxStart)) != std::string::npos) | ||
610 | { | ||
611 | strText.replace(idxCur + idxOffset, lenFrom, strTo); | ||
612 | idxStart = idxCur + lenFrom; | ||
613 | idxOffset += lenTo - lenFrom; | ||
614 | } | ||
615 | } | ||
616 | |||
617 | // Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b | ||
618 | std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch /*=NULL*/) | ||
619 | { | ||
620 | if (pidxMatch) | ||
621 | *pidxMatch = std::string::npos; // Assume we won't find anything | ||
622 | |||
623 | std::string::size_type idxIt, idxStart; int cntLevel = 1; | ||
624 | if ((idxStart = strText.find_first_of('(')) == std::string::npos) | ||
625 | return std::string(); | ||
626 | |||
627 | const char* pstrText = strText.c_str(); idxIt = idxStart; | ||
628 | while ( (cntLevel > 0) && (idxIt < strText.length()) ) | ||
629 | { | ||
630 | if ('(' == pstrText[++idxIt]) | ||
631 | cntLevel++; | ||
632 | else if (')' == pstrText[idxIt]) | ||
633 | cntLevel--; | ||
634 | } | ||
635 | |||
636 | if (idxIt < strText.length()) | ||
637 | { | ||
638 | if (pidxMatch) | ||
639 | *pidxMatch = idxStart; // Return the character index of the starting '(' | ||
640 | return strText.substr(idxStart + 1, idxIt - idxStart - 1); | ||
641 | } | ||
642 | return std::string(); | ||
643 | } | ||
644 | |||
645 | // Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b | ||
646 | std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart /*=NULL*/) | ||
647 | { | ||
648 | if (pidxStart) | ||
649 | *pidxStart = std::string::npos; // Assume we won't find anything | ||
650 | |||
651 | // Extracts the last - matched - parenthesised text from the input string | ||
652 | std::string::size_type idxIt, idxEnd; int cntLevel = 1; | ||
653 | if ((idxEnd = strText.find_last_of(')')) == std::string::npos) | ||
654 | return std::string(); | ||
655 | |||
656 | const char* pstrText = strText.c_str(); idxIt = idxEnd; | ||
657 | while ( (cntLevel > 0) && (idxIt >= 0) ) | ||
658 | { | ||
659 | if (')' == pstrText[--idxIt]) | ||
660 | cntLevel++; | ||
661 | else if ('(' == pstrText[idxIt]) | ||
662 | cntLevel--; | ||
663 | } | ||
664 | |||
665 | if ( (idxIt >= 0) && (idxIt < strText.length()) ) // NOTE: allow for std::string::size_type to be signed or unsigned | ||
666 | { | ||
667 | if (pidxStart) | ||
668 | *pidxStart = idxIt; // Return the character index of the starting '(' | ||
669 | return strText.substr(idxIt + 1, idxEnd - idxIt - 1); | ||
670 | } | ||
671 | return std::string(); | ||
672 | } | ||
673 | |||
674 | // ========================================================================= | ||