diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llprimitive/llprimitive.cpp | 219 | ||||
-rw-r--r-- | linden/indra/llprimitive/llprimitive.h | 2 | ||||
-rw-r--r-- | linden/indra/newview/app_settings/settings.xml | 50 | ||||
-rw-r--r-- | linden/indra/newview/llagent.cpp | 5 | ||||
-rw-r--r-- | linden/indra/newview/llappviewer.cpp | 9 | ||||
-rw-r--r-- | linden/indra/newview/llfirstuse.cpp | 34 | ||||
-rw-r--r-- | linden/indra/newview/llfirstuse.h | 2 | ||||
-rw-r--r-- | linden/indra/newview/llstartup.cpp | 2 | ||||
-rw-r--r-- | linden/indra/newview/llvoavatar.cpp | 262 | ||||
-rw-r--r-- | linden/indra/newview/llvoavatar.h | 11 | ||||
-rw-r--r-- | linden/indra/newview/skins/default/xui/en-us/notifications.xml | 18 |
11 files changed, 602 insertions, 12 deletions
diff --git a/linden/indra/llprimitive/llprimitive.cpp b/linden/indra/llprimitive/llprimitive.cpp index 6fc0a55..c2d1d1e 100644 --- a/linden/indra/llprimitive/llprimitive.cpp +++ b/linden/indra/llprimitive/llprimitive.cpp | |||
@@ -958,16 +958,213 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai | |||
958 | 958 | ||
959 | U32 old_face_mask = mVolumep->mFaceMask; | 959 | U32 old_face_mask = mVolumep->mFaceMask; |
960 | 960 | ||
961 | S32 face_bit = 0; | ||
962 | S32 cur_mask = 0; | ||
963 | |||
964 | // grab copies of the old faces so we can determine the TE mappings... | ||
965 | std::vector<LLProfile::Face> old_faces; // list of old faces for remapping texture entries | ||
966 | LLTextureEntry old_tes[9]; | ||
967 | |||
968 | for (S32 face = 0; face < mVolumep->getNumFaces(); face++) | ||
969 | { | ||
970 | old_faces.push_back(mVolumep->getProfile().mFaces[face]); | ||
971 | } | ||
972 | |||
973 | for (face_bit = 0; face_bit < 9; face_bit++) | ||
974 | { | ||
975 | cur_mask = 0x1 << face_bit; | ||
976 | if (old_face_mask & cur_mask) | ||
977 | { | ||
978 | S32 te_index = face_index_from_id(cur_mask, old_faces); | ||
979 | old_tes[face_bit] = *getTE(te_index); | ||
980 | //llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl; | ||
981 | } | ||
982 | } | ||
983 | |||
984 | |||
961 | // build the new object | 985 | // build the new object |
962 | sVolumeManager->unrefVolume(mVolumep); | 986 | sVolumeManager->unrefVolume(mVolumep); |
963 | mVolumep = volumep; | 987 | mVolumep = volumep; |
964 | 988 | ||
965 | U32 new_face_mask = mVolumep->mFaceMask; | 989 | U32 new_face_mask = mVolumep->mFaceMask; |
966 | if (old_face_mask != new_face_mask) | 990 | S32 i; |
991 | |||
992 | /* | ||
993 | std::string old_mask_string; | ||
994 | for (i = 0; i < 9; i++) | ||
995 | { | ||
996 | if (old_face_mask & (1 << i)) | ||
997 | { | ||
998 | old_mask_string.append("1"); | ||
999 | } | ||
1000 | else | ||
1001 | { | ||
1002 | old_mask_string.append("0"); | ||
1003 | } | ||
1004 | } | ||
1005 | std::string new_mask_string; | ||
1006 | for (i = 0; i < 9; i++) | ||
1007 | { | ||
1008 | if (new_face_mask & (1 << i)) | ||
1009 | { | ||
1010 | new_mask_string.append("1"); | ||
1011 | } | ||
1012 | else | ||
1013 | { | ||
1014 | new_mask_string.append("0"); | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | llinfos << "old mask: " << old_mask_string << llendl; | ||
1019 | llinfos << "new mask: " << new_mask_string << llendl; | ||
1020 | */ | ||
1021 | |||
1022 | |||
1023 | if (old_face_mask == new_face_mask) | ||
967 | { | 1024 | { |
1025 | // nothing to do | ||
1026 | return TRUE; | ||
1027 | } | ||
1028 | |||
1029 | if (mVolumep->getNumFaces() == 0 && new_face_mask != 0) | ||
1030 | { | ||
1031 | llwarns << "Object with 0 faces found...INCORRECT!" << llendl; | ||
968 | setNumTEs(mVolumep->getNumFaces()); | 1032 | setNumTEs(mVolumep->getNumFaces()); |
969 | } | 1033 | return TRUE; |
970 | 1034 | } | |
1035 | |||
1036 | |||
1037 | S32 face_mapping[9]; | ||
1038 | for (face_bit = 0; face_bit < 9; face_bit++) | ||
1039 | { | ||
1040 | face_mapping[face_bit] = face_bit; | ||
1041 | } | ||
1042 | |||
1043 | // Generate the face-type mappings | ||
1044 | for (face_bit = 0; face_bit < 9; face_bit++) | ||
1045 | { | ||
1046 | cur_mask = 0x1 << face_bit; | ||
1047 | if (!(new_face_mask & cur_mask)) | ||
1048 | { | ||
1049 | // Face doesn't exist in new map. | ||
1050 | face_mapping[face_bit] = -1; | ||
1051 | continue; | ||
1052 | } | ||
1053 | else if (old_face_mask & cur_mask) | ||
1054 | { | ||
1055 | // Face exists in new and old map. | ||
1056 | face_mapping[face_bit] = face_bit; | ||
1057 | continue; | ||
1058 | } | ||
1059 | |||
1060 | // OK, how we've got a mismatch, where we have to fill a new face with one from | ||
1061 | // the old face. | ||
1062 | if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE)) | ||
1063 | { | ||
1064 | // It's a top/bottom/hollow interior face. | ||
1065 | if (old_face_mask & LL_FACE_PATH_END) | ||
1066 | { | ||
1067 | face_mapping[face_bit] = 1; | ||
1068 | continue; | ||
1069 | } | ||
1070 | else | ||
1071 | { | ||
1072 | S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; | ||
1073 | for (i = 0; i < 4; i++) | ||
1074 | { | ||
1075 | if (old_face_mask & cur_outer_mask) | ||
1076 | { | ||
1077 | face_mapping[face_bit] = 5 + i; | ||
1078 | break; | ||
1079 | } | ||
1080 | cur_outer_mask <<= 1; | ||
1081 | } | ||
1082 | if (i == 4) | ||
1083 | { | ||
1084 | llwarns << "No path end or outer face in volume!" << llendl; | ||
1085 | } | ||
1086 | continue; | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) | ||
1091 | { | ||
1092 | // A cut slice. Use the hollow interior if we have it. | ||
1093 | if (old_face_mask & LL_FACE_INNER_SIDE) | ||
1094 | { | ||
1095 | face_mapping[face_bit] = 2; | ||
1096 | continue; | ||
1097 | } | ||
1098 | |||
1099 | // No interior, use the bottom face. | ||
1100 | // Could figure out which of the outer faces was nearest, but that would be harder. | ||
1101 | if (old_face_mask & LL_FACE_PATH_END) | ||
1102 | { | ||
1103 | face_mapping[face_bit] = 1; | ||
1104 | continue; | ||
1105 | } | ||
1106 | else | ||
1107 | { | ||
1108 | S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0; | ||
1109 | for (i = 0; i < 4; i++) | ||
1110 | { | ||
1111 | if (old_face_mask & cur_outer_mask) | ||
1112 | { | ||
1113 | face_mapping[face_bit] = 5 + i; | ||
1114 | break; | ||
1115 | } | ||
1116 | cur_outer_mask <<= 1; | ||
1117 | } | ||
1118 | if (i == 4) | ||
1119 | { | ||
1120 | llwarns << "No path end or outer face in volume!" << llendl; | ||
1121 | } | ||
1122 | continue; | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | // OK, the face that's missing is an outer face... | ||
1127 | // Pull from the nearest adjacent outer face (there's always guaranteed to be one... | ||
1128 | S32 cur_outer = face_bit - 5; | ||
1129 | S32 min_dist = 5; | ||
1130 | S32 min_outer_bit = -1; | ||
1131 | S32 i; | ||
1132 | for (i = 0; i < 4; i++) | ||
1133 | { | ||
1134 | if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i)) | ||
1135 | { | ||
1136 | S32 dist = abs(i - cur_outer); | ||
1137 | if (dist < min_dist) | ||
1138 | { | ||
1139 | min_dist = dist; | ||
1140 | min_outer_bit = i + 5; | ||
1141 | } | ||
1142 | } | ||
1143 | } | ||
1144 | if (-1 == min_outer_bit) | ||
1145 | { | ||
1146 | llinfos << (LLVolume *)mVolumep << llendl; | ||
1147 | llwarns << "Bad! No outer faces, impossible!" << llendl; | ||
1148 | } | ||
1149 | face_mapping[face_bit] = min_outer_bit; | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | setNumTEs(mVolumep->getNumFaces()); | ||
1154 | for (face_bit = 0; face_bit < 9; face_bit++) | ||
1155 | { | ||
1156 | cur_mask = 0x1 << face_bit; | ||
1157 | if (new_face_mask & cur_mask) | ||
1158 | { | ||
1159 | if (-1 == face_mapping[face_bit]) | ||
1160 | { | ||
1161 | llwarns << "No mapping from old face to new face!" << llendl; | ||
1162 | } | ||
1163 | |||
1164 | S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces); | ||
1165 | setTE(te_num, old_tes[face_mapping[face_bit]]); | ||
1166 | } | ||
1167 | } | ||
971 | return TRUE; | 1168 | return TRUE; |
972 | } | 1169 | } |
973 | 1170 | ||
@@ -1135,7 +1332,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat | |||
1135 | // Pack information about all texture entries into container: | 1332 | // Pack information about all texture entries into container: |
1136 | // { TextureEntry Variable 2 } | 1333 | // { TextureEntry Variable 2 } |
1137 | // Includes information about image ID, color, scale S,T, offset S,T and rotation | 1334 | // Includes information about image ID, color, scale S,T, offset S,T and rotation |
1138 | BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const | 1335 | BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys, bool shield) const |
1139 | { | 1336 | { |
1140 | const U32 MAX_TES = 32; | 1337 | const U32 MAX_TES = 32; |
1141 | 1338 | ||
@@ -1164,7 +1361,17 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const | |||
1164 | for (face_index = 0; face_index <= last_face_index; face_index++) | 1361 | for (face_index = 0; face_index <= last_face_index; face_index++) |
1165 | { | 1362 | { |
1166 | // Directly sending image_ids is not safe! | 1363 | // Directly sending image_ids is not safe! |
1167 | memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16); /* Flawfinder: ignore */ | 1364 | if(shield && !(face_index == 4 || face_index == 8 || face_index == 9 || face_index == 10 || face_index == 11 || face_index == 18 || face_index == 19)) |
1365 | { | ||
1366 | S8 f_f_i = face_index; | ||
1367 | if(face_index == 0)f_f_i = 64; | ||
1368 | if(face_index == 5)f_f_i = 9; | ||
1369 | if(face_index == 6)f_f_i = 10; | ||
1370 | if(face_index == 3)f_f_i = 11; | ||
1371 | if(f_f_i == face_index)memcpy(&image_ids[face_index*16],LLUUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97").mData,16); | ||
1372 | else if(f_f_i == 64)memcpy(&image_ids[face_index*16],LLUUID("2a9a406c-f448-68f2-4e38-878f8c46c190").mData,16);//Imprudence FIXME: example | ||
1373 | else memcpy(&image_ids[face_index*16],LLUUID("4934f1bf-3b1f-cf4f-dbdf-a72550d05bc6").mData,16);//grey block | ||
1374 | }else memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16); /* Flawfinder: ignore */ | ||
1168 | 1375 | ||
1169 | // Cast LLColor4 to LLColor4U | 1376 | // Cast LLColor4 to LLColor4U |
1170 | coloru.setVec( getTE(face_index)->getColor() ); | 1377 | coloru.setVec( getTE(face_index)->getColor() ); |
diff --git a/linden/indra/llprimitive/llprimitive.h b/linden/indra/llprimitive/llprimitive.h index cc86f5b..cf9ff0f 100644 --- a/linden/indra/llprimitive/llprimitive.h +++ b/linden/indra/llprimitive/llprimitive.h | |||
@@ -339,7 +339,7 @@ public: | |||
339 | void copyTEs(const LLPrimitive *primitive); | 339 | void copyTEs(const LLPrimitive *primitive); |
340 | S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; | 340 | S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; |
341 | S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type); | 341 | S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type); |
342 | BOOL packTEMessage(LLMessageSystem *mesgsys) const; | 342 | BOOL packTEMessage(LLMessageSystem *mesgsys, bool shield = false) const; |
343 | BOOL packTEMessage(LLDataPacker &dp) const; | 343 | BOOL packTEMessage(LLDataPacker &dp) const; |
344 | S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name); | 344 | S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name); |
345 | S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, const S32 block_num); // Variable num of blocks | 345 | S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, const S32 block_num); // Variable num of blocks |
diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml index 12d052c..fc0a903 100644 --- a/linden/indra/newview/app_settings/settings.xml +++ b/linden/indra/newview/app_settings/settings.xml | |||
@@ -1,6 +1,56 @@ | |||
1 | <?xml version="1.0" ?> | 1 | <?xml version="1.0" ?> |
2 | <llsd> | 2 | <llsd> |
3 | <map> | 3 | <map> |
4 | |||
5 | <!-- Begin: Client Name Tag --> | ||
6 | |||
7 | <key>ShowClientNameTag</key> | ||
8 | <map> | ||
9 | <key>Comment</key> | ||
10 | <string>Show others clients in name tag</string> | ||
11 | <key>Persist</key> | ||
12 | <integer>1</integer> | ||
13 | <key>Type</key> | ||
14 | <string>Boolean</string> | ||
15 | <key>Value</key> | ||
16 | <integer>1</integer> | ||
17 | </map> | ||
18 | <key>DownloadClientTags</key> | ||
19 | <map> | ||
20 | <key>Comment</key> | ||
21 | <string>download tags</string> | ||
22 | <key>Persist</key> | ||
23 | <integer>1</integer> | ||
24 | <key>Type</key> | ||
25 | <string>Boolean</string> | ||
26 | <key>Value</key> | ||
27 | <integer>0</integer> | ||
28 | </map> | ||
29 | <key>WarnClientTags</key> | ||
30 | <map> | ||
31 | <key>Comment</key> | ||
32 | <string>Enables ClientTags warning dialog</string> | ||
33 | <key>Persist</key> | ||
34 | <integer>1</integer> | ||
35 | <key>Type</key> | ||
36 | <string>Boolean</string> | ||
37 | <key>Value</key> | ||
38 | <integer>1</integer> | ||
39 | </map> | ||
40 | <key>ClothingLayerProtection</key> | ||
41 | <map> | ||
42 | <key>Comment</key> | ||
43 | <string>Overwrites clothing layers to sim in order to protect your worn items from being as easily stolen. Also lets others see the client name if set to true.</string> | ||
44 | <key>Persist</key> | ||
45 | <integer>1</integer> | ||
46 | <key>Type</key> | ||
47 | <string>Boolean</string> | ||
48 | <key>Value</key> | ||
49 | <integer>1</integer> | ||
50 | </map> | ||
51 | |||
52 | <!-- End: Client Name Tag --> | ||
53 | |||
4 | <key>RestrainedLife</key> | 54 | <key>RestrainedLife</key> |
5 | <map> | 55 | <map> |
6 | <key>Comment</key> | 56 | <key>Comment</key> |
diff --git a/linden/indra/newview/llagent.cpp b/linden/indra/newview/llagent.cpp index 800264d..0b9f646 100644 --- a/linden/indra/newview/llagent.cpp +++ b/linden/indra/newview/llagent.cpp | |||
@@ -7386,7 +7386,10 @@ void LLAgent::sendAgentSetAppearance() | |||
7386 | msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); | 7386 | msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); |
7387 | } | 7387 | } |
7388 | msg->nextBlockFast(_PREHASH_ObjectData); | 7388 | msg->nextBlockFast(_PREHASH_ObjectData); |
7389 | mAvatarObject->packTEMessage( gMessageSystem ); | 7389 | mAvatarObject->packTEMessage ( |
7390 | gMessageSystem, | ||
7391 | gSavedSettings.getBOOL("ClothingLayerProtection") | ||
7392 | ); | ||
7390 | } | 7393 | } |
7391 | else | 7394 | else |
7392 | { | 7395 | { |
diff --git a/linden/indra/newview/llappviewer.cpp b/linden/indra/newview/llappviewer.cpp index 05d4db9..7976388 100644 --- a/linden/indra/newview/llappviewer.cpp +++ b/linden/indra/newview/llappviewer.cpp | |||
@@ -739,6 +739,15 @@ bool LLAppViewer::init() | |||
739 | // | 739 | // |
740 | initWindow(); | 740 | initWindow(); |
741 | 741 | ||
742 | { | ||
743 | BOOL download = gSavedSettings.getBOOL("DownloadClientTags"); | ||
744 | |||
745 | if(download) | ||
746 | { | ||
747 | LLVOAvatar::updateClientTags(); | ||
748 | } | ||
749 | } | ||
750 | |||
742 | // call all self-registered classes | 751 | // call all self-registered classes |
743 | LLInitClassList::instance().fireCallbacks(); | 752 | LLInitClassList::instance().fireCallbacks(); |
744 | 753 | ||
diff --git a/linden/indra/newview/llfirstuse.cpp b/linden/indra/newview/llfirstuse.cpp index bea9260..877e586 100644 --- a/linden/indra/newview/llfirstuse.cpp +++ b/linden/indra/newview/llfirstuse.cpp | |||
@@ -45,6 +45,8 @@ | |||
45 | #include "llappviewer.h" | 45 | #include "llappviewer.h" |
46 | #include "lltracker.h" | 46 | #include "lltracker.h" |
47 | 47 | ||
48 | #include "llvoavatar.h" | ||
49 | |||
48 | // [RLVa:KB] - Version: 1.22.11 | 50 | // [RLVa:KB] - Version: 1.22.11 |
49 | #include "llviewerwindow.h" | 51 | #include "llviewerwindow.h" |
50 | // [/RLVa:KB] | 52 | // [/RLVa:KB] |
@@ -292,3 +294,35 @@ void LLFirstUse::useMedia() | |||
292 | LLNotifications::instance().add("FirstMedia"); | 294 | LLNotifications::instance().add("FirstMedia"); |
293 | } | 295 | } |
294 | } | 296 | } |
297 | void LLFirstUse::callbackClientTags(const LLSD& notification, const LLSD& response) | ||
298 | { | ||
299 | gSavedSettings.setWarning("ClientTags", FALSE); | ||
300 | |||
301 | S32 option = LLNotification::getSelectedOption(notification, response); | ||
302 | |||
303 | //LLFloaterAvatarList *avlist = LLFloaterAvatarList::sInstance; | ||
304 | |||
305 | if ( option == 0 ) | ||
306 | { | ||
307 | gSavedSettings.setBOOL("DownloadClientTags",TRUE); | ||
308 | //printchat("The tags will not be updated until you restart."); | ||
309 | //fuck that shit | ||
310 | LLVOAvatar::updateClientTags(); | ||
311 | LLVOAvatar::loadClientTags(); | ||
312 | //boom | ||
313 | //toasty | ||
314 | } | ||
315 | else if ( option == 1 ) | ||
316 | { | ||
317 | gSavedSettings.setBOOL("DownloadClientTags",FALSE); | ||
318 | } | ||
319 | } | ||
320 | // static | ||
321 | void LLFirstUse::ClientTags() | ||
322 | { | ||
323 | if (gSavedSettings.getWarning("ClientTags")) | ||
324 | { | ||
325 | LLNotifications::instance().add("QueryClientTags", LLSD(), LLSD(), callbackClientTags); | ||
326 | } | ||
327 | } | ||
328 | |||
diff --git a/linden/indra/newview/llfirstuse.h b/linden/indra/newview/llfirstuse.h index 3305ffe..e327984 100644 --- a/linden/indra/newview/llfirstuse.h +++ b/linden/indra/newview/llfirstuse.h | |||
@@ -111,6 +111,8 @@ public: | |||
111 | static void useDebugMenus(); | 111 | static void useDebugMenus(); |
112 | static void useSculptedPrim(); | 112 | static void useSculptedPrim(); |
113 | static void useMedia(); | 113 | static void useMedia(); |
114 | static void callbackClientTags(const LLSD& notification, const LLSD& response); | ||
115 | static void ClientTags(); | ||
114 | 116 | ||
115 | protected: | 117 | protected: |
116 | static std::set<std::string> sConfigVariables; | 118 | static std::set<std::string> sConfigVariables; |
diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp index c5bf2c7..143aa34 100644 --- a/linden/indra/newview/llstartup.cpp +++ b/linden/indra/newview/llstartup.cpp | |||
@@ -2582,6 +2582,8 @@ bool idle_startup() | |||
2582 | { | 2582 | { |
2583 | set_startup_status(1.0, "", ""); | 2583 | set_startup_status(1.0, "", ""); |
2584 | 2584 | ||
2585 | LLFirstUse::ClientTags(); | ||
2586 | |||
2585 | // Let the map know about the inventory. | 2587 | // Let the map know about the inventory. |
2586 | if(gFloaterWorldMap) | 2588 | if(gFloaterWorldMap) |
2587 | { | 2589 | { |
diff --git a/linden/indra/newview/llvoavatar.cpp b/linden/indra/newview/llvoavatar.cpp index 7e1c6ca..5f63443 100644 --- a/linden/indra/newview/llvoavatar.cpp +++ b/linden/indra/newview/llvoavatar.cpp | |||
@@ -83,6 +83,8 @@ | |||
83 | #include "llvoiceclient.h" | 83 | #include "llvoiceclient.h" |
84 | #include "llvoicevisualizer.h" // Ventrella | 84 | #include "llvoicevisualizer.h" // Ventrella |
85 | 85 | ||
86 | #include "llsdserialize.h" // client resolver | ||
87 | |||
86 | #if LL_WINDOWS | 88 | #if LL_WINDOWS |
87 | // Disable warning for unreachable code in boost/lexical_cast.hpp for Boost 1.36 -- McCabe | 89 | // Disable warning for unreachable code in boost/lexical_cast.hpp for Boost 1.36 -- McCabe |
88 | #pragma warning(disable : 4702) | 90 | #pragma warning(disable : 4702) |
@@ -678,6 +680,7 @@ S32 LLVOAvatar::sScratchTexBytes = 0; | |||
678 | F32 LLVOAvatar::sRenderDistance = 256.f; | 680 | F32 LLVOAvatar::sRenderDistance = 256.f; |
679 | S32 LLVOAvatar::sNumVisibleAvatars = 0; | 681 | S32 LLVOAvatar::sNumVisibleAvatars = 0; |
680 | S32 LLVOAvatar::sNumLODChangesThisFrame = 0; | 682 | S32 LLVOAvatar::sNumLODChangesThisFrame = 0; |
683 | LLSD LLVOAvatar::sClientResolutionList; | ||
681 | 684 | ||
682 | const LLUUID LLVOAvatar::sStepSoundOnLand = LLUUID("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); | 685 | const LLUUID LLVOAvatar::sStepSoundOnLand = LLUUID("e8af4a28-aa83-4310-a7c4-c047e15ea0df"); |
683 | const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = | 686 | const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = |
@@ -1402,6 +1405,9 @@ void LLVOAvatar::initClass() | |||
1402 | llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; | 1405 | llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; |
1403 | } | 1406 | } |
1404 | 1407 | ||
1408 | { | ||
1409 | loadClientTags(); | ||
1410 | } | ||
1405 | } | 1411 | } |
1406 | 1412 | ||
1407 | 1413 | ||
@@ -2971,6 +2977,239 @@ void LLVOAvatar::idleUpdateWindEffect() | |||
2971 | } | 2977 | } |
2972 | } | 2978 | } |
2973 | } | 2979 | } |
2980 | bool LLVOAvatar::updateClientTags() | ||
2981 | { | ||
2982 | std::string client_list_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "client_list.xml"); | ||
2983 | //Imprudence FIXME: provide own ressource | ||
2984 | LLSD response = LLHTTPClient::blockingGet("http://www.modularsystems.sl/app/client_tags/client_list.xml"); | ||
2985 | if(response.has("body")) | ||
2986 | { | ||
2987 | const LLSD &client_list = response["body"]; | ||
2988 | |||
2989 | if(client_list.has("isComplete")) | ||
2990 | { | ||
2991 | llofstream export_file; | ||
2992 | export_file.open(client_list_filename); | ||
2993 | LLSDSerialize::toPrettyXML(client_list, export_file); | ||
2994 | export_file.close(); | ||
2995 | return true; | ||
2996 | } | ||
2997 | } | ||
2998 | return false; | ||
2999 | } | ||
3000 | |||
3001 | bool LLVOAvatar::loadClientTags() | ||
3002 | { | ||
3003 | std::string client_list_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "client_list.xml"); | ||
3004 | |||
3005 | if(!LLFile::isfile(client_list_filename)) | ||
3006 | { | ||
3007 | client_list_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "client_list.xml"); | ||
3008 | } | ||
3009 | |||
3010 | if(LLFile::isfile(client_list_filename)) | ||
3011 | { | ||
3012 | LLSD client_list; | ||
3013 | |||
3014 | llifstream importer(client_list_filename); | ||
3015 | LLSDSerialize::fromXMLDocument(client_list, importer); | ||
3016 | if(client_list.has("isComplete")) | ||
3017 | { | ||
3018 | sClientResolutionList = client_list; | ||
3019 | }else | ||
3020 | { | ||
3021 | return false; | ||
3022 | } | ||
3023 | }else | ||
3024 | { | ||
3025 | return false; | ||
3026 | } | ||
3027 | |||
3028 | for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); | ||
3029 | iter != LLCharacter::sInstances.end(); ++iter) | ||
3030 | { | ||
3031 | LLVOAvatar* avatarp = (LLVOAvatar*) *iter; | ||
3032 | if(avatarp) | ||
3033 | { | ||
3034 | LLVector3 root_pos_last = avatarp->mRoot.getWorldPosition(); | ||
3035 | avatarp->idleUpdateNameTag(root_pos_last); | ||
3036 | } | ||
3037 | } | ||
3038 | return true; | ||
3039 | } | ||
3040 | |||
3041 | void LLVOAvatar::resolveClient(LLColor4& avatar_name_color, std::string& client, LLVOAvatar* avatar) | ||
3042 | { | ||
3043 | LLUUID idx = avatar->getTE(0)->getID(); | ||
3044 | if(LLVOAvatar::sClientResolutionList.has("isComplete") | ||
3045 | && LLVOAvatar::sClientResolutionList.has(idx.asString())) | ||
3046 | { | ||
3047 | LLSD cllsd = LLVOAvatar::sClientResolutionList[idx.asString()]; | ||
3048 | client = cllsd["name"].asString(); | ||
3049 | LLColor4 colour; | ||
3050 | colour.setValue(cllsd["color"]); | ||
3051 | avatar_name_color += colour; | ||
3052 | avatar_name_color *= 1.0/(cllsd["multiple"].asReal()+1.0f); | ||
3053 | } | ||
3054 | else | ||
3055 | { | ||
3056 | /* | ||
3057 | //Imprudence FIXME: we need a inworld UUID for that | ||
3058 | //and it needs also to be at llprimitive/llprimitive.cpp (find "Imprudence FIXME" there) | ||
3059 | |||
3060 | if(idx == LLUUID("")) | ||
3061 | { | ||
3062 | avatar_name_color += LLColor4(0.6f,0.8f,1.0f);//Imprudence | ||
3063 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3064 | client = "Imprudence"; | ||
3065 | |||
3066 | } else | ||
3067 | */ | ||
3068 | if(idx == LLUUID("2a9a406c-f448-68f2-4e38-878f8c46c190")) | ||
3069 | { | ||
3070 | avatar_name_color += LLColor4(1.0f,0.9f,0.7f);//Meerkat | ||
3071 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3072 | client = "Meerkat"; | ||
3073 | }else if(idx == LLUUID("ccda2b3b-e72c-a112-e126-fee238b67218")) | ||
3074 | { | ||
3075 | avatar_name_color += LLColor4::green;//emerald | ||
3076 | avatar_name_color += LLColor4::green; | ||
3077 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3078 | client = "Emerald"; | ||
3079 | }else if(idx == LLUUID("c252d89d-6f7c-7d90-f430-d140d2e3fbbe")) | ||
3080 | { | ||
3081 | avatar_name_color += LLColor4::red;//vlife jcool410 | ||
3082 | avatar_name_color = avatar_name_color * 0.5; | ||
3083 | client = "VLife"; | ||
3084 | }else if(idx == LLUUID("adcbe893-7643-fd12-f61c-0b39717e2e32")) | ||
3085 | { | ||
3086 | avatar_name_color += LLColor4::pink;//tyk3n | ||
3087 | avatar_name_color = avatar_name_color * 0.5; | ||
3088 | client = "tyk3n"; | ||
3089 | }else if(idx == LLUUID("f3fd74a6-fee7-4b2f-93ae-ddcb5991da04") || idx == LLUUID("77662f23-c77a-9b4d-5558-26b757b2144c")) | ||
3090 | { | ||
3091 | avatar_name_color += (LLColor4::purple);//psl | ||
3092 | avatar_name_color = avatar_name_color * 0.5; | ||
3093 | client = "PSL"; | ||
3094 | }else if(idx == LLUUID("5aa5c70d-d787-571b-0495-4fc1bdef1500")) | ||
3095 | { | ||
3096 | avatar_name_color += LLColor4::red;//lordgreg | ||
3097 | avatar_name_color += LLColor4::red; | ||
3098 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3099 | client = "LGG proxy"; | ||
3100 | }else if(idx == LLUUID("8183e823-c443-2142-6eb6-2ab763d4f81c")) | ||
3101 | { | ||
3102 | avatar_name_color += LLColor4::blue;//day oh | ||
3103 | avatar_name_color = avatar_name_color * 0.5; | ||
3104 | client = "Day Oh proxy"; | ||
3105 | }else if(idx == LLUUID("e52d21f7-3c8b-819f-a3db-65c432295dac") || idx == LLUUID("0f6723d2-5b23-6b58-08ab-308112b33786")) | ||
3106 | { | ||
3107 | avatar_name_color += LLColor4::cyan;//cryolife | ||
3108 | avatar_name_color += LLColor4::cyan; | ||
3109 | avatar_name_color = avatar_name_color * 0.5; | ||
3110 | client = "CryoLife"; | ||
3111 | }else if(idx == LLUUID("0bcd5f5d-a4ce-9ea4-f9e8-15132653b3d8")) | ||
3112 | { | ||
3113 | avatar_name_color += LLColor4::pink;//moy | ||
3114 | avatar_name_color += LLColor4::pink;//moy | ||
3115 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3116 | client = "MoyMix"; | ||
3117 | }else if(idx == LLUUID("f5a48821-9a98-d09e-8d6a-50cc08ba9a47")) | ||
3118 | { | ||
3119 | avatar_name_color += LLColor4::yellow;//neil | ||
3120 | avatar_name_color += LLColor4::yellow;//neil | ||
3121 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3122 | client = "NeilLife"; | ||
3123 | }else if(idx == LLUUID("2c9c1e0b-e5d1-263e-16b1-7fc6d169f3d6")) | ||
3124 | { | ||
3125 | avatar_name_color += LLColor4(0.0f,1.0f,1.0f); | ||
3126 | avatar_name_color = avatar_name_color * 0.5;//phox | ||
3127 | client = "PhoxSL"; | ||
3128 | }else if(idx == LLUUID("c5b570ca-bb7e-3c81-afd1-f62646b20014") || idx == LLUUID("7c4d47a3-0c51-04d1-fa47-e4f3ac12f59b")) | ||
3129 | { | ||
3130 | avatar_name_color += LLColor4::white; | ||
3131 | avatar_name_color += LLColor4::white; | ||
3132 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3133 | client = "Kung Fu"; | ||
3134 | }else if(idx == LLUUID("9422e9d7-7b11-83e4-6262-4a8db4716a3b")) | ||
3135 | { | ||
3136 | avatar_name_color += LLColor4::magenta; | ||
3137 | avatar_name_color += LLColor4::magenta; | ||
3138 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3139 | client = "BetaLife"; | ||
3140 | }else if(idx == LLUUID("872c0005-3095-0967-866d-11cd71115c22")) | ||
3141 | { | ||
3142 | avatar_name_color += LLColor4::green;//SimFed Poland | ||
3143 | avatar_name_color += LLColor4::blue;//SimFed Poland | ||
3144 | avatar_name_color += LLColor4::blue;//SimFed Poland | ||
3145 | avatar_name_color = avatar_name_color * 0.5; | ||
3146 | client = "<-- Fag"; | ||
3147 | |||
3148 | //Imprudence FIXME: Cigarette? Homophobic? My lack of humor? | ||
3149 | |||
3150 | }else if(idx == LLUUID("3ab7e2fa-9572-ef36-1a30-d855dbea4f92") || //wat | ||
3151 | idx == LLUUID("11ad2452-ce54-8d65-7c23-05589b59f516") ||//wat. | ||
3152 | idx == LLUUID("e734563e-1c31-2a35-3ed5-8552c807439f") ||//wat. | ||
3153 | idx == LLUUID("58a8b7ec-1455-7162-5d96-d3c3ead2ed71") ||//wat | ||
3154 | idx == LLUUID("841ef25b-3b90-caf9-ea3d-5649e755db65")//wat -.- | ||
3155 | ) | ||
3156 | { | ||
3157 | avatar_name_color += LLColor4(0.0f,0.5f,1.0f); | ||
3158 | avatar_name_color = avatar_name_color * 0.5; | ||
3159 | client = "VerticalLife"; | ||
3160 | |||
3161 | |||
3162 | }else if(idx == LLUUID("4e8dcf80-336b-b1d8-ef3e-08dacf015a0f")) | ||
3163 | { | ||
3164 | avatar_name_color += LLColor4::blue; //Sapphire | ||
3165 | avatar_name_color += LLColor4::blue; //Sapphire | ||
3166 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3167 | client = "Sapphire"; | ||
3168 | }else if(idx == LLUUID("ffce04ff-5303-4909-a044-d37af7ab0b0e")) | ||
3169 | { | ||
3170 | avatar_name_color += LLColor4::orange; //corgiVision | ||
3171 | avatar_name_color = avatar_name_color * (F32)0.75; | ||
3172 | client = "Corgi"; | ||
3173 | }else if(idx == LLUUID("ccb509cf-cc69-e569-38f1-5086c687afd1")) | ||
3174 | { | ||
3175 | avatar_name_color += LLColor4::red; //Ruby | ||
3176 | avatar_name_color += LLColor4::purple; //Ruby | ||
3177 | avatar_name_color = avatar_name_color * (F32)0.333333333333; | ||
3178 | client = "Ruby"; | ||
3179 | }else if(idx == LLUUID("1c29480c-c608-df87-28bb-964fb64c5366")) | ||
3180 | { | ||
3181 | avatar_name_color += LLColor4::yellow9; | ||
3182 | avatar_name_color += LLColor4::yellow9; | ||
3183 | avatar_name_color *= (F32)0.333333333333; | ||
3184 | client = "Gemini"; | ||
3185 | } | ||
3186 | } | ||
3187 | if(client.empty()) | ||
3188 | { | ||
3189 | LLPointer<LLViewerImage> image_point = gImageList.getImage(idx, MIPMAP_YES, IMMEDIATE_NO); | ||
3190 | if(image_point.notNull() && image_point->isMissingAsset()) | ||
3191 | { | ||
3192 | avatar_name_color += LLColor4::grey;//anomalous | ||
3193 | avatar_name_color = avatar_name_color * 0.5; | ||
3194 | client = "Invalid"; | ||
3195 | } | ||
3196 | } | ||
3197 | if(avatar->getTE(5)->getID() != avatar->getTE(6)->getID() && !client.empty()) | ||
3198 | { | ||
3199 | client = "Failure"; | ||
3200 | avatar_name_color = LLColor4::grey; | ||
3201 | } | ||
3202 | if(client.empty() && LLVOAvatar::sClientResolutionList.has("default")) | ||
3203 | { | ||
3204 | LLSD cllsd = LLVOAvatar::sClientResolutionList["default"]; | ||
3205 | client = cllsd["name"].asString(); | ||
3206 | LLColor4 colour; | ||
3207 | colour.setValue(cllsd["color"]); | ||
3208 | avatar_name_color += colour; | ||
3209 | avatar_name_color *= 1.0/(cllsd["multiple"].asReal()+1.0f); | ||
3210 | } | ||
3211 | |||
3212 | } | ||
2974 | 3213 | ||
2975 | void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | 3214 | void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) |
2976 | { | 3215 | { |
@@ -3032,7 +3271,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3032 | mRenderGroupTitles = sRenderGroupTitles; | 3271 | mRenderGroupTitles = sRenderGroupTitles; |
3033 | new_name = TRUE; | 3272 | new_name = TRUE; |
3034 | } | 3273 | } |
3035 | 3274 | std::string client; | |
3036 | // First Calculate Alpha | 3275 | // First Calculate Alpha |
3037 | // If alpha > 0, create mNameText if necessary, otherwise delete it | 3276 | // If alpha > 0, create mNameText if necessary, otherwise delete it |
3038 | { | 3277 | { |
@@ -3073,6 +3312,11 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3073 | } | 3312 | } |
3074 | 3313 | ||
3075 | LLColor4 avatar_name_color = gColors.getColor( "AvatarNameColor" ); | 3314 | LLColor4 avatar_name_color = gColors.getColor( "AvatarNameColor" ); |
3315 | if(!mIsSelf) //don't know your own client ? | ||
3316 | { | ||
3317 | new_name = TRUE; //lol or see the last client used | ||
3318 | resolveClient(avatar_name_color,client, this); | ||
3319 | } | ||
3076 | avatar_name_color.setAlpha(alpha); | 3320 | avatar_name_color.setAlpha(alpha); |
3077 | mNameText->setColor(avatar_name_color); | 3321 | mNameText->setColor(avatar_name_color); |
3078 | 3322 | ||
@@ -3129,7 +3373,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3129 | (!title && !mTitle.empty()) || | 3373 | (!title && !mTitle.empty()) || |
3130 | (title && mTitle != title->getString()) || | 3374 | (title && mTitle != title->getString()) || |
3131 | (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) | 3375 | (is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) |
3132 | || is_appearance != mNameAppearance) | 3376 | || is_appearance != mNameAppearance || client.length() != 0) |
3133 | { | 3377 | { |
3134 | std::string line; | 3378 | std::string line; |
3135 | 3379 | ||
@@ -3158,7 +3402,8 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3158 | 3402 | ||
3159 | BOOL need_comma = FALSE; | 3403 | BOOL need_comma = FALSE; |
3160 | 3404 | ||
3161 | if (is_away || is_muted || is_busy) | 3405 | bool show_client = client.length() != 0 && gSavedSettings.getBOOL("ShowClientNameTag"); |
3406 | if (is_away || is_muted || is_busy || show_client) | ||
3162 | { | 3407 | { |
3163 | line += " ("; | 3408 | line += " ("; |
3164 | if (is_away) | 3409 | if (is_away) |
@@ -3184,6 +3429,15 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) | |||
3184 | line += "Muted"; | 3429 | line += "Muted"; |
3185 | need_comma = TRUE; | 3430 | need_comma = TRUE; |
3186 | } | 3431 | } |
3432 | if (show_client) | ||
3433 | { | ||
3434 | if (need_comma) | ||
3435 | { | ||
3436 | line += ", "; | ||
3437 | } | ||
3438 | line += client; | ||
3439 | need_comma = TRUE; | ||
3440 | } | ||
3187 | line += ")"; | 3441 | line += ")"; |
3188 | } | 3442 | } |
3189 | if (is_appearance) | 3443 | if (is_appearance) |
@@ -7438,6 +7692,8 @@ void LLVOAvatar::releaseUnnecessaryTextures() | |||
7438 | { | 7692 | { |
7439 | const LLVOAvatarDictionary::BakedDictionaryEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); | 7693 | const LLVOAvatarDictionary::BakedDictionaryEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); |
7440 | // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID | 7694 | // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID |
7695 | if(baked_index == BAKED_HEAD)//for client detection | ||
7696 | continue; | ||
7441 | if (!isTextureDefined(bakedDicEntry->mTextureIndex) | 7697 | if (!isTextureDefined(bakedDicEntry->mTextureIndex) |
7442 | && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) )) | 7698 | && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) )) |
7443 | { | 7699 | { |
diff --git a/linden/indra/newview/llvoavatar.h b/linden/indra/newview/llvoavatar.h index f6d5e27..f759e15 100644 --- a/linden/indra/newview/llvoavatar.h +++ b/linden/indra/newview/llvoavatar.h | |||
@@ -534,6 +534,8 @@ public: | |||
534 | LLViewerJoint mRoot; // avatar skeleton | 534 | LLViewerJoint mRoot; // avatar skeleton |
535 | BOOL mIsSitting; // sitting state | 535 | BOOL mIsSitting; // sitting state |
536 | 536 | ||
537 | static bool updateClientTags(); | ||
538 | static bool loadClientTags(); | ||
537 | //-------------------------------------------------------------------- | 539 | //-------------------------------------------------------------------- |
538 | // Private member variables. | 540 | // Private member variables. |
539 | //-------------------------------------------------------------------- | 541 | //-------------------------------------------------------------------- |
@@ -590,12 +592,19 @@ private: | |||
590 | 592 | ||
591 | // Animation timer | 593 | // Animation timer |
592 | LLTimer mAnimTimer; | 594 | LLTimer mAnimTimer; |
593 | F32 mTimeLast; | 595 | F32 mTimeLast; |
596 | |||
594 | 597 | ||
595 | // Send selection beam info to scripts | 598 | // Send selection beam info to scripts |
596 | static int sPartsNow; | 599 | static int sPartsNow; |
597 | static LLVector3d sBeamLastAt; | 600 | static LLVector3d sBeamLastAt; |
601 | static LLSD sClientResolutionList; | ||
602 | |||
603 | static void resolveClient(LLColor4& avatar_name_color, std::string& client, LLVOAvatar* avatar); | ||
604 | //Imprudence FIXME | ||
605 | // friend class LLFloaterAvatarList; | ||
598 | 606 | ||
607 | protected: | ||
599 | LLPointer<LLHUDEffectSpiral> mBeam; | 608 | LLPointer<LLHUDEffectSpiral> mBeam; |
600 | LLFrameTimer mBeamTimer; | 609 | LLFrameTimer mBeamTimer; |
601 | 610 | ||
diff --git a/linden/indra/newview/skins/default/xui/en-us/notifications.xml b/linden/indra/newview/skins/default/xui/en-us/notifications.xml index e8391ba..9678e8f 100644 --- a/linden/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/linden/indra/newview/skins/default/xui/en-us/notifications.xml | |||
@@ -6384,6 +6384,24 @@ Add this Ability to '[ROLE_NAME]'? | |||
6384 | </notification> | 6384 | </notification> |
6385 | 6385 | ||
6386 | <notification | 6386 | <notification |
6387 | icon="notify.tga" | ||
6388 | name="QueryClientTags" | ||
6389 | type="notify"> | ||
6390 | Would you like to have the client tag database automatically updated from modularsystems.sl? | ||
6391 | This ensures that you have the latest information available regarding other clients. | ||
6392 | <form name="form"> | ||
6393 | <button | ||
6394 | index="0" | ||
6395 | name="Yes" | ||
6396 | text="Yes"/> | ||
6397 | <button | ||
6398 | index="1" | ||
6399 | name="No" | ||
6400 | text="No"/> | ||
6401 | </form> | ||
6402 | </notification> | ||
6403 | |||
6404 | <notification | ||
6387 | icon="notifytip.tga" | 6405 | icon="notifytip.tga" |
6388 | name="UnableToOpenCommandURL" | 6406 | name="UnableToOpenCommandURL" |
6389 | priority="high" | 6407 | priority="high" |