diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..849d99dfa3d98a4a00ad255b86a5ab19edb4f6e4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,29 @@ +* text=auto + +# Sources +*.cpp text diff=cpp +*.h text diff=cpp +*.py text diff=python + +# Documents +*.txt text +*.xml text + +# Graphics +*.png binary diff=exif +*.jpg binary diff=exif +*.jpeg binary diff=exif +*.gif binary diff=exif +*.tif binary +*.tiff binary +*.ico binary +*.svg text +*.eps binary + +# Scripts +*.sh text eol=lf +*.bat text eol=crlf + +# Exclude files from exporting +.gitattributes export-ignore +.gitignore export-ignore diff --git a/.gitignore b/.gitignore index 27b629a578c0f410ffd187c2babda05f5c9eaa56..7d4a125a8a6195fdc5f063b8ffb5f0ba20f8ace3 100755 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,4 @@ libraries tarfile_tmp web/config.* web/locale.* -web/secondlife.com.* \ No newline at end of file +web/secondlife.com.* diff --git a/.hgtags b/.hgtags deleted file mode 100755 index beb2da41912f978861a92fa77dade6a14fd65577..0000000000000000000000000000000000000000 --- a/.hgtags +++ /dev/null @@ -1,559 +0,0 @@ -003dd9461bfa479049afcc34545ab3431b147c7c v2start -52d96ad3d39be29147c5b2181b3bb46af6164f0e alpha-3 -d6781e22543acd7e21b967209f3c6e7003d380e3 fork to viewer-2-0 -7f16e79826d377f5f9f5b33dc721ab56d0d7dc8f alpha-4 -7f16e79826d377f5f9f5b33dc721ab56d0d7dc8f fork to viewer-20qa -d40ac9dd949cba6dab1cc386da6a2027690c2519 alpha-5 -d2382d374139850efa5bb6adfb229e3e656cfc40 howard-demo -b8419565906e4feb434426d8d9b17dd1458e24b2 alpha-6 -17fc2908e9a1ef34a9f53a41a393caf5c3cac390 beta-3-5 -3469d90a115b900f8f250e137bbd9b684130f5d2 beta-4 -12769e547e30067d494a6c01479a18107366ce2f beta-5 -4f777ffb99fefdc6497c61385c22688ff149c659 viewer-2-0-0 -668851b2ef0f8cf8df07a0fba429e4a6c1e70abb viewer-2-0-1 -08398e650c222336bb2b6de0cd3bba944aef11b4 2-1rn1 -80bc6cff515118a36108967af49d3f8105c95bc9 viewer-2-0-2-start -46002088d9a4489e323b8d56131c680eaa21258c viewer-2-1-0-start -3e4b947f79d88c385e8218cbc0731cef0e42cfc4 2-1-beta-1 -0962101bfa7df0643a6e625786025fe7f8a6dc97 2-1-beta-2 -1e2b517adc2ecb342cd3c865f2a6ccf82a3cf8d7 2-1-beta-3 -c6969fe44e58c542bfc6f1bd6c0be2fa860929ac 2-1-beta-4 -b03065d018b8a2e28b7de85b293a4c992cb4c12d 2-1-release -19547b909b404552593be5ec7c18241e062a6d65 2-1-1-beta-1 -6e3b2e13906ba8ff22d3c8490b02d518adb2c907 2-1-1-beta-2 -bb38ff1a763738609e1b3cada6d15fa61e5e84b9 2-1-1-release -bb38ff1a763738609e1b3cada6d15fa61e5e84b9 2.1.1-release -c6e6324f5be1401f077ad18a4a0f6b46451c2f7b last_sprint -7076e22f9f43f479a4ea75eac447a36364bead5a 2.2.0-beta1 -7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1 -7076e22f9f43f479a4ea75eac447a36364bead5a beta_2.1.3 -9822eb3e25f7fe0c28ffd8aba45c507caa383cbc 2.2.0-beta2 -9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2 -b0cd7e150009809a0b5b0a9d5785cd4bb230413a 2.2.0-beta3 -b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3 -00a831292231faad7e44c69f76cb96f175b8dfad 2.2.0-beta4 -1415e6538d54fd5d568ee88343424d57c6803c2c 2.2.0-release -1415e6538d54fd5d568ee88343424d57c6803c2c DRTVWR-8_2.2.0-release -98e0d6df638429fd2f0476667504bd5a6b298def 2.3.0-start -a3c12342b1af0951b8aa3b828aacef17fcea8178 2.3.0-beta1 -a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1 -db0fe9bb65187f365e58a717dd23d0f4754a9c1d 2.3.0-beta2 -db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2 -6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 2.3.0-beta3 -6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 2.3.0-release -6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-13_2.3.0-release -6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-20_2.3.0-beta3 -dbc206fc61d89ff4cfe15aade0bf0c7bc7fee1c9 2.4.0-start -3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e 2.4.0-beta1 -3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e DRTVWR-26_2.4.0-beta1 -25bd6007e3d2fc15db9326ed4b18a24a5969a46a 2.4.0-beta2 -25bd6007e3d2fc15db9326ed4b18a24a5969a46a DRTVWR-27_2.4.0-beta2 -1ed382c6a08ba3850b6ce9061bc551ddece0ea07 2.4.0-release -1ed382c6a08ba3850b6ce9061bc551ddece0ea07 DRTVWR-25_2.4.0-release -a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start -345b17e7cf630db77e840b4fe3451bd476d750a3 2.5.0-beta1 -345b17e7cf630db77e840b4fe3451bd476d750a3 DRTVWR-32_2.5.0-beta1 -54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2 -54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f DRTVWR-33--2.5.0beta2 -54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f DRTVWR-33_2.5.0-beta2 -b723921b5c711bd24dbe77dc76ef488b544dac78 2.5.0-beta3 -b723921b5c711bd24dbe77dc76ef488b544dac78 2.5.0-release -b723921b5c711bd24dbe77dc76ef488b544dac78 DRTVWR-31_2.5.0-release -b723921b5c711bd24dbe77dc76ef488b544dac78 DRTVWR-34_2.5.0-beta3 -b542f8134a2bb5dd054ff4e509a44b2ee463b1bf nat-eventapi2-base -63a6aedfce785a6c760377bf685b2dae616797d2 2.5.1-start -4dede9ae1ec74d41f6887719f6f1de7340d8578d 2.5.1-release -4dede9ae1ec74d41f6887719f6f1de7340d8578d DRTVWR-37_2.5.1-release -b53a0576eec80614d7767ed72b40ed67aeff27c9 2.5.2-release -b53a0576eec80614d7767ed72b40ed67aeff27c9 DRTVWR-38_2.5.2-release -4e9eec6a347f89b2b3f295beb72f1cf7837dff66 2.6.0-start -9283d6d1d7eb71dfe4c330e7c9144857e7356bde 2.6.0-beta1 -9283d6d1d7eb71dfe4c330e7c9144857e7356bde DRTVWR-40_2.6.0-beta1 -461c8c65b5c799ddfe365422f9be9c0095d91e7d 2.6.0-beta1-tip -9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2 -9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2 -42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release -42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release -c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-beta1 -c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start -c5bdef3aaa2744626aef3c217ce29e1900d357b3 DRTVWR-43_2.6.1-beta1 -c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release -c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release -56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start -d1203046bb653b763f835b04d184646949d8dd5c 2.6.2-beta1 -d1203046bb653b763f835b04d184646949d8dd5c DRTVWR-45_2.6.2-beta1 -214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release -214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release -52b2263ab28f0976c689fd0b76c55a9eb027cdbf end-of-develop.py -ec32f1045e7c2644015245df3a9933620aa194b8 2.6.3-start -d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1 -d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc DRTVWR-47_2.6.3-beta1 -0630e977504af5ea320c58d33cae4e1ddee793e9 2.6.3-beta2 -0630e977504af5ea320c58d33cae4e1ddee793e9 DRTVWR-48_2.6.3-beta2 -8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release -8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release -3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work -7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd 2.6.5-beta1 -7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd DRTVWR-50_2.6.5-beta1 -800cefce8d364ffdd2f383cbecb91294da3ea424 2.6.6-start -bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 2.6.6-beta1 -bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 DRTVWR-52_2.6.6-beta1 -dac76a711da5f1489a01c1fa62ec97d99c25736d 2.6.6-release -dac76a711da5f1489a01c1fa62ec97d99c25736d DRTVWR-51_2.6.6-release -5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start -beafa8a9bd1d1b670b7523d865204dc4a4b38eef 2.6.8-beta1 -beafa8a9bd1d1b670b7523d865204dc4a4b38eef DRTVWR-55_2.6.8-beta1 -be2000b946f8cb3de5f44b2d419287d4c48ec4eb 2.6.8-release -be2000b946f8cb3de5f44b2d419287d4c48ec4eb DRTVWR-54_2.6.8-release -e67da2c6e3125966dd49eef98b36317afac1fcfe 2.6.9-start -77e5a08344c95738ab879f9671b7758cddd712a3 2.6.9-beta1 -77e5a08344c95738ab879f9671b7758cddd712a3 2.6.9-release -77e5a08344c95738ab879f9671b7758cddd712a3 DRTVWR-56_2.6.9-release -77e5a08344c95738ab879f9671b7758cddd712a3 DRTVWR-57_2.6.9-beta1 -8835e0e3c0d3a48244c287bc05811dfc2fba43ec 2.7.0-start -43c7ee846b7eed80786acbbf35d03bd016a3e85d 2.7.0-beta1 -43c7ee846b7eed80786acbbf35d03bd016a3e85d DRTVWR-59_2.7.0-beta1 -54fd44ac92e4c61435ea33effe093a3527e18d98 2.7.1-start -0c4d0c24278074f219e5a32e72b449e78301d11b 2.7.1-beta1 -0c4d0c24278074f219e5a32e72b449e78301d11b DRTVWR-61_2.7.1-beta1 -9f79a6ed8fdcd2f3dac33ea6b3236eeb278dccfe 2.7.2-start -e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1 -e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1 -fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.1-release -fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.2-release -fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-60_2.7.1-release -fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-62_2.7.2-release -6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start -6af10678de4736222b2c3f7e010e984fb5b327de 2.7.4-start -be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1 -be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1 -057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release -057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release -19a498fa62570f352d7d246f17e3c81cc1d82d8b 2.7.5-start -09984bfa6cae17e0f72d02b75c1b7393c65eecfc 2.7.5-beta1 -09984bfa6cae17e0f72d02b75c1b7393c65eecfc DRTVWR-69_2.7.5-beta1 -6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release -6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release -e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-beta1 -e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-start -e1ed60913230dd64269a7f7fc52cbc6004f6d52c DRTVWR-71_2.8.0-beta1 -493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release -493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release -502f6a5deca9365ddae57db4f1e30172668e171e 2.8.1-start -2c7e459e0c883f8e406b932e41e60097e9ee077e 2.8.1-beta1 -2c7e459e0c883f8e406b932e41e60097e9ee077e DRTVWR-73_2.8.1-beta1 -29e93d7e19991011bd12b5748142b11a5dcb4370 2.8.1-release -29e93d7e19991011bd12b5748142b11a5dcb4370 DRTVWR-72_2.8.1-release -4780e3bd2b3042f91be3426151f28c30d199bb3b 2.8.1-hotfix -4780e3bd2b3042f91be3426151f28c30d199bb3b DRTVWR-76_2.8.1-hotfix -54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start -ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start -599677276b227357140dda35bea4a2c18e2e67b5 2.8.3-beta1 -599677276b227357140dda35bea4a2c18e2e67b5 DRTVWR-75_2.8.3-beta1 -fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release -fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release -6b678ea52f90d5c14181661dcd2546e25bde483e 3.0.0-start -b0be6ce3adfef3a014a2389d360539f8a86c5439 3.0.0-beta1 -b0be6ce3adfef3a014a2389d360539f8a86c5439 DRTVWR-78_3.0.0-beta1 -1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release -1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release -82a2079ffcb57ecb1b3849cb41376b443e1eb912 3.0.1-start -364fd63517fbacbbcb9129d096187171ba8c9e48 3.0.1-beta1 -364fd63517fbacbbcb9129d096187171ba8c9e48 DRTVWR-81_3.0.1-beta1 -f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start -42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1 -42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1 -e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2 -e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2 -b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start -6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 3.0.3-beta1 -6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1 -61aa7974df089e8621fe9a4c69bcdefdb3cc208a 3.0.3-beta2 -61aa7974df089e8621fe9a4c69bcdefdb3cc208a DRTVWR-89_3.0.3-beta2 -0496d2f74043cf4e6058e76ac3db03d44cff42ce 3.0.3-release -0496d2f74043cf4e6058e76ac3db03d44cff42ce DRTVWR-84_3.0.3-release -586907287be581817b2422b5137971b22d54ea48 3.0.4-start -92a3aa04775438226399b19deee12ac3b5a62838 3.0.5-start -c7282e59f374ee904bd793c3c444455e3399b0c5 3.1.0-start -2657fa785bbfac115852c41bd0adaff74c2ad5da 3.1.0-beta1 -2657fa785bbfac115852c41bd0adaff74c2ad5da DRTVWR-93_3.1.0-beta1 -bc01ee26fd0f1866e266429e85f76340523e91f1 3.1.0-beta2 -bc01ee26fd0f1866e266429e85f76340523e91f1 DRTVWR-96_3.1.0-beta2 -ae2de7b0b33c03dc5bdf3a7bfa54463b512221b2 3.1.0-release -ae2de7b0b33c03dc5bdf3a7bfa54463b512221b2 DRTVWR-92_3.1.0-release -a8230590e28e4f30f5105549e0e43211d9d55711 3.2.0-start -e440cd1dfbd128d7d5467019e497f7f803640ad6 3.2.0-beta1 -e440cd1dfbd128d7d5467019e497f7f803640ad6 DRTVWR-95_3.2.0-beta1 -9bcc2b7176634254e501e3fb4c5b56c1f637852e 3.2.0-beta2 -9bcc2b7176634254e501e3fb4c5b56c1f637852e DRTVWR-97_3.2.0-beta2 -2a13d30ee50ccfed50268238e36bb90d738ccc9e 3.2.0-beta3 -2a13d30ee50ccfed50268238e36bb90d738ccc9e DRTVWR-98_3.2.0-beta3 -3150219d229d628f0c15e58e8a51511cbd97e58d 3.2.0-release -3150219d229d628f0c15e58e8a51511cbd97e58d DRTVWR-94_3.2.0-release -c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start -9e390d76807fa70d356b8716fb83b8ce42a629ef 3.2.1-beta1 -9e390d76807fa70d356b8716fb83b8ce42a629ef DRTVWR-100_3.2.1-beta1 -a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release -a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release -40b46edba007d15d0059c80864b708b99c1da368 3.2.2-start -523df3e67378541498d516d52af4402176a26bac 3.2.2-beta1 -523df3e67378541498d516d52af4402176a26bac DRTVWR-102_3.2.2-beta1 -80f3e30d8aa4d8f674a48bd742aaa6d8e9eae0b5 3.2.3-start -3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-beta1 -3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-start -3fe994349fae64fc40874bb59db387131eb35a41 DRTVWR-104_3.2.4-beta1 -bd6bcde2584491fd9228f1fa51c4575f4e764e19 3.2.4-release -bd6bcde2584491fd9228f1fa51c4575f4e764e19 DRTVWR-103_3.2.4-release -8a44ff3d2104269ce76145c2772cf1bdff2a2abe 3.2.5-start -3d2d5d244c6398a4214c666d5dd3965b0918709a 3.2.5-beta1 -3d2d5d244c6398a4214c666d5dd3965b0918709a DRTVWR-106_3.2.5-beta1 -65a2c1c8d855b88edfbea4e16ef2f27e7cff8b1d 3.2.5-beta2 -65a2c1c8d855b88edfbea4e16ef2f27e7cff8b1d DRTVWR-107_3.2.5-beta2 -c6175c955a19e9b9353d242889ec1779b5762522 3.2.5-release -c6175c955a19e9b9353d242889ec1779b5762522 DRTVWR-105_3.2.5-release -2174ed1c7129562428a5cfe8651ed77b8d26ae18 3.2.6-start -286d73ff5c19f6c00e023dc1b60975ed6bbe2872 3.2.6-beta1 -286d73ff5c19f6c00e023dc1b60975ed6bbe2872 DRTVWR-109_3.2.6-beta1 -4891c46a56fed7512c783b9cbe7cb7260727bf0c 3.2.7-start -3d75c836d178c7c7e788f256afe195f6cab764a2 3.2.7-beta1 -3d75c836d178c7c7e788f256afe195f6cab764a2 DRTVWR-111_3.2.7-beta1 -89980333c99dbaf1787fe20784f1d8849e9b5d4f 3.2.8-start -16f8e2915f3f2e4d732fb3125daf229cb0fd1875 3.2.8-beta1 -16f8e2915f3f2e4d732fb3125daf229cb0fd1875 DRTVWR-114_3.2.8-beta1 -987425b1acf4752379b2e1eb20944b4b35d67a85 3.2.8-beta2 -987425b1acf4752379b2e1eb20944b4b35d67a85 DRTVWR-115_3.2.8-beta2 -51b2fd52e36aab8f670e0874e7e1472434ec4b4a 3.2.8-release -51b2fd52e36aab8f670e0874e7e1472434ec4b4a DRTVWR-113_3.2.8-release -37dd400ad721e2a89ee820ffc1e7e433c68f3ca2 3.2.9-start -e9c82fca5ae6fb8a8af29012d78fb194a29323f3 3.2.9-beta1 -e9c82fca5ae6fb8a8af29012d78fb194a29323f3 DRTVWR-117_3.2.9-beta1 -a01ef9bed28627f4ca543fbc1d70c79cc297a90f 3.2.9-beta2 -a01ef9bed28627f4ca543fbc1d70c79cc297a90f DRTVWR-118_3.2.9-beta2 -d5f263687f43f278107363365938f0a214920a4b 3.3.0-beta1 -d5f263687f43f278107363365938f0a214920a4b 3.3.0-start -d5f263687f43f278107363365938f0a214920a4b DRTVWR-119 -5e8d2662f38a66eca6c591295f5880d47afc73f7 3.3.0-release -3e2fca4ed1a0dc9fe6d8a6664e71098bb035a367 3.3.1-start -3e2fca4ed1a0dc9fe6d8a6664e71098bb035a367 DRTVWR-125 -28b95a6a28dca3338d9a1f4f204b96678df9f6a5 3.3.1-beta1 -1dc545e44617975da2a4a32fe303386c687a6ca1 3.3.1-beta2 -1dc545e44617975da2a4a32fe303386c687a6ca1 DRTVWR-139 -1dc545e44617975da2a4a32fe303386c687a6ca1 viewer-beta-candidate -c623bbc854b6f7ee1b33a3718f76715046aa2937 3.3.1-release -d29a260119f8d5a5d168e25fed0c7ea6b3f40161 3.3.2-beta1 -675668bd24d3bea570814f71762a2a806f7e1b8d 3.3.2-beta2 -675668bd24d3bea570814f71762a2a806f7e1b8d 3.3.2-release -15e90b52dc0297921b022b90d10d797436b8a1bd viewer-release-candidate -bb9932a7a5fd00edf52d95f354e3b37ae6a942db DRTVWR-156 -6414ecdabc5d89515b08d1f872cf923ed3a5523a DRTVWR-148 -2a3965b3ad202df7ea25d2be689291bb14a1280e DRTVWR-155 -24a7281bef42bd4430ceb25db8b195449c2c7de3 DRTVWR-153 -5910f8063a7e1ddddf504c2f35ca831cc5e8f469 DRTVWR-160 -f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 3.3.3-beta1 -f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 DRTVWR-144 -2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164 -600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162 -80b5e5e9775966d3839331ffa7a16a60f9d7c930 DRTVWR-165 -fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2 -af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169 -4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3 -6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release -a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 -9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157 -089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161 -c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163 -b9d0170b62eb1c7c3adaa37a0b13a833e5e659f9 DRTVWR-171 -050e48759337249130f684b4a21080b683f61732 DRTVWR-168 -09ef7fd1b0781f33b8a3a9af6236b7bcb4831910 DRTVWR-170 -f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 DRTVWR-158 -f91d003091a61937a044652c4c674447f7dcbb7a 3.3.4-beta1 -bce218b2b45b730b22cc51e4807aa8b571cadef3 DRTVWR-173 -cbea6356ce9cb0c313b6777f10c5c14783264fcc DRTVWR-174 -82b5330bc8b17d0d4b598832e9c5a92e90075682 3.3.4-beta2 -57d221de3df94f90b55204313c2cef044a3c0ae2 DRTVWR-176 -eb539c65e6ee26eea2bf373af2d0f4b52dc91289 DRTVWR-177 -a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3 -4281aa899fb2cedb7a9ca7ce91c5c29d4aa69594 DRTVWR-180 -5c08e1d8edd871807153603b690e3ee9dbb548aa DRTVWR-183 -6c75f220b103db1420919c8b635fe53e2177f318 3.3.4-beta4 -9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184 -ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5 -28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release -6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199 -7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2 -8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207 -351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3 -005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167 -888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175 -a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182 -1f27cdfdc54246484f8afbbe42ce48e954175cbd 3.4.0-beta1 -9ee9387789701d597130f879d9011a4958753862 DRTVWR-189 -47f0d08ba7ade0a3905074009067c6d3df7e16ae DRTVWR-190 -421126293dcbde918e0da027ca0ab9deb5b4fbf2 DRTVWR-192 -33a2fc7a910ae29ff8b4850316ed7fbff9f64d33 DRTVWR-195 -e9732c739c8a72a590216951505ea9c76a526a84 DRTVWR-193 -7602f61c804a512764e349c034c02ddabeefebc4 DRTVWR-196 -ae5c83dd61d2d37c45f1d5b8bf2b036d87599f1b DRTVWR-198 -507bdfbd6bf844a511c1ffeda4baa80016ed1346 DRTVWR-197 -b1dbb1a83f48f93f6f878cff9e52d2cb635e145c 3.4.0-beta2 -37402e2b19af970d51b0a814d79892cc5647532b DRTVWR-200 -182a9bf30e81070361bb020a78003b1cf398e79c 3.4.0-beta3 -7649a3dff5ec22d3727377e5f02efd0f421e4cb5 DRTVWR-201 -84fb70dfe3444e75a44fb4bee43e2fc8221cebdd 3.4.0-beta4 -573e863be2f26d3687161def4b9fea9b7038dda8 3.4.0-beta5 -af7b28e75bd5a629cd9e0dc46fb3f1757626f493 DRTVWR-212 -015012c2b740ccdec8a8c3d6e5f898449ecfe0b8 DRTVWR-213 -62b07aa81b1957897c3846292bb9412977b0af6c 3.3.4-beta6 -ceed0b65a69f1eac20d523e0203320a32f9a3f3c DRTVWR-215 -733ceac77583874f3626ef7a15c105b83ef0f5bb 3.4.0-beta7 -97977c67245f52db20eb15f1918cc0f24778cabc 3.4.0-release -5adb2b8f96c3cac88ad7c7d996d707f1b29df336 3.4.1-beta1 -b3f74858a1c8720c82d0978f3877a3fc8ba459ec 3.4.1-beta1a -2b779f233ee6f38c89cb921650c773a96e63da92 DRTVWR-220 -0b9d95f4bfb6867cbf56eaec51633b0da2f1262d DRTVWR-221 -e6e553761829dc0270eaaa712b7cb0622535b076 3.4.1-beta3 -f00068a66a2e2f72acbe3f690b98b323e740b289 DRTVWR-222 -305950187c628a5d6743ee9ea711cc5b9177a18e 3.4.1-beta4 -dd23d4da3bcb2ffda58569e759feb7c119982973 DRTVWR-224 -0bd3744ff060452aa13ff4992eafb381df7b1012 3.4.1-beta5 -29075f8c1abed53dcf195a59f61744e27a91108f DRTVWR-226 -fba99f381b8d4ad1b7b42fa4993b29998d95be18 DRTVWR-179 -49ed253c80bed7410e238eeab35a9f14cb034364 3.4.1-beta6 -468ca3268229011a59df99229b24315844b33d34 DRTVWR-227 -524da902713e8b60322640b9825101add4a7c497 3.4.1-beta7 -173c2809f9873499c4b9d6bc044ec941c954d3fb DRTVWR-228 -1dc94555582f52718834081e7659e973ae4521f7 3.4.1-beta8 -52c164c8023a5e65f3dc1b0bbb7fa1dd0c631b6b DRTVWR-231 -464cf7a63a9a2f95bc4972dc022ca765e93de7d3 DRTVWR-233 -637fe8bbee5e24940448198c221d5ee0fa3247b4 3.4.1-beta9 -4e0d84e92132e9e95a1d52a1e49bad69c278ea05 3.4.1-beta10 -f7cbd60a3f57ff1101157eeb79ea21e8898bedae DRTVWR-235 -baf97f06ae17223614c5e31aa42e71d87cff07fe DRTVWR-236 -18498afcdb835d6fc4d36ed935347d3b65307bad 3.4.1-beta11 -b2f21e3442542283a80e7eaebae9f833e5a927b6 DRTVWR-237 -3f9be82de642d468c5fc272cb9d96b46b5498402 3.4.1-beta12 -e59ffd3fe0838ae6b09b242a6e9df71761b88f41 3.4.1-release -81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 -cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 -c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 -4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191 -78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194 -248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203 -de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202 -34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag -6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 -7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206 -b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219 -32896d5e920ca9a29256ff3b747c2e99752aa5ae DRTVWR-217 -704bbae7b182a1f2811a47a054e680522966f54a 3.4.2-beta1 -288539fc0408ed4b69a99665de33bbbc2c3c08fe DRTVWR-216 -e664473c16df1d82ffaff382e7b3e023da202d52 3.4.2-beta2 -0891d7a773a31397dcad48be3fa66531d567a821 DRTVWR-242 -710785535362b3cb801b6a3dc4703be3373bd0cd 3.4.2-beta3 -e9a5886052433d5db9e504ffaca10890f9932979 DRTVWR-243 -73b84b9864dc650fe7c8fc9f52361450f0849004 3.4.2-beta4 -16310aabccf315870f7cc9bf966926c0ad6954fa 3.4.2-release -d799593b53ed733862e9a13871e318e886469377 DRTVWR-208 -e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223 -93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240 -2aa72e3372a83dece4df9cf72fb1e7c34f90b5e3 DRTVWR-209 -f7bedce18ad52283e6072814db23318907261487 DRTVWR-238 -7b64c96fbcadf360bd2feaae19d330166b70877c DRTVWR-210 -5e4e4128b256525bafc07a62e35ae8527aaa9c9d DRTVWR-241 -f1d3b3fcab28ed9ea532bf50db0ba96f5c8cc8e9 DRTVWR-232 -4918b150e75df6b516fb6c2616d32043fa6b4cac DRTVWR-245 -94ab2b49458ab372a95d2d6949fdf574f413068d 3.4.3-beta1 -965b9a35e260c0f53be1a25f0db7abc8a67eaf47 DRTVWR-252 -bb10adc4f76cf0067fca7075146f00cdc0740e9d DRTVWR-251 -ab0aa2f6ba22b52fed30a2337197f589156edc75 DRTVWR-253 -48382ec79741671d19ce4cc3e8cd59e9a521e4a7 DRTVWR-254 -937ec902bb9a1cbceff17bd89e3923352b0a5fbc DRTVWR-256 -44e764a6ac9e672a4f3bce821a4b6a218590c374 DRTVWR-258 -c23d734065ed593b2413385aecd8366d8e0ee96b DRTVWR-257 -452ce96d4046dc05a3ecaecc203e2cc8ddd72e76 DRTVWR-259 -daca610d840625b5bebb966a57cb49581852c417 DRTVWR-265 -9afbdc4e24cc04feacfb2b7a10b78a64f780901a DRTVWR-266 -73280db02501f5ad041fc18b1eba68e73a81996c DRTVWR-267 -870e2d79e0063fda87187f17bbc2747766733194 3.4.3-beta3 -0a2ca6546b499239afeb66d17b2fadbcdbe36ab1 3.4.3-release -4c3460cb1fb7c6da9965e09c734d282a8e9c81f0 DRTVWR-229 -f4481df42f9a4a92bf475a80f0c51d1a4bbdfd59 DRTVWR-246 -39c5204b6e800983a41ccac8ad6dc993120197c6 DRTVWR-247 -7c7d57d393e8ae7b61623279de06eb4a62ccae6a DRTVWR-249 -f72b50ef168c159d6e79e97aa2bcafaf8577ab99 DRTVWR-230 -b418be80903520c492e1173f3afbc4021cad5d07 DRTVWR-255 -9aa1aa9f1fe13c194695a0b8f0af298296241dc2 DRTVWR-260 -84fbaf2d4141bd161731430e760949dc787ca206 DRTVWR-244 -083d2d36b5bb1c54fc3dd7caac0e7ac381a9cef0 3.4.4-beta1 -b634dec987c16e8c9c938e11e52591d9ead8fa9b DRTVWR-270 -cd39255bd23330fd30c04105f2811e941d8524fe 3.4.4-beta2 -2c4011bbc2b15b82198fd8b51f3a9fe765a08c4d DRTVWR-271 -2f8a3ef687bc55828abcb17ac1ad7cde70536d7e 3.4.4-beta3 -35cfd4cf5b895fa776592f2e630e330be7f0604e DRTVWR-273 -c374035d459af3c03dea2dd90880dfc25de64706 DRTVWR-275 -05d9f1dd7a954069af2a33abedb7713fa36a04cb 3.4.4-beta4 -e1bb1ae7d8b12faeb37933a737c199cc9b9f89cc 3.4.4-release -391a8c74cec7275c5d26c85ad108d4782a3e3dd9 DRTVWR-268 -a36f1f354b02aa6e448ca13685de167d0a0a3d03 DRTVWR-272 -37dba00ad820de3a808d4039396b162a9c275b3e DRTVWR-269 -7c6dfdc1b7a2ce0d8e3a8f3ce3058547ea065c0f DRTVWR-250 -b9ff9730daa53a541925300cbd02bb14575a5705 DRTVWR-277 -af6b711a97073431953b55ee808aaa09900c27e5 DRTVWR-276 -8302fefde6c8f4a64bfc7f04929f8bc85f5c6c7b DRTVWR-279 -c296133849d1f103c0e2abc41e6599daed00b67b DRTVWR-280 -40a2265058abc9fde4914c10185f916435818621 3.4.5-beta1 -5df4802bec93c8d0a509946d826bb4c50c5442ec DRTVWR-281 -7c1c33ba4cfd2d15ca51cc1ac440eca551331a4a DRTVWR-283 -6b9c7dbebef793230d64e1b452577c8b142d4143 3.4.5-beta2 -ccf991e02dc2f63fb646324230d54832683f4a9b DRTVWR-286 -2d849850558a5a0324b398d1c102d30bcbdfb88f DRTVWR-287 -e06898df8644fe567bee94f817d03abc1c380993 3.4.5-beta3 -a676b4d6c037b39fe5b8e42cf8839a9303936089 DRTVWR-289 -28fa8b944a0c1869636ab00cc400f5aa71f6fa3c DRTVWR-290 -7f09bbc28c297f14b67961be7b6575445fa160e8 DRTVWR-291 -b23419a2748483c98f3b84b630468a21c88feba5 DRTVWR-292 -1567de5700c273b583dac41b64275c223287306e 3.4.5-beta4 -1cce8447f8f574673e3f47d6fe584262e6964fe2 DRTVWR-296 -0a5d409161ef2a89b28c9a741051dd2dedc707d6 DRTVWR-297 -852b69ef0b5fe6b13b69cc2217282cc64de6afab 3.4.5-beta5 -a49c715243a36a8a380504d14cb7416b3039c956 3.4.5-release -37947e4f771f001b551581bf7cd0051c3153beed DRTVWR-282 -6482cceb91cda68b799f3e6cdc66d33bf123547a DRTVWR-284 -092a9effbedd1a0276fa5ced520992ce00f96fbf CHUI-PV-0 -279ef1dfc9b749a6cc499cf190fec0c090b6d682 DRTVWR-288 -9b19edaf1d8ddf435f60fbbb444dd25db8f63953 3.5.0-beta1 -c6b3561c7d7ad365eeba669db54eb57b5149ce75 3.5.0-beta2 -6d91ffd77bf2a20f18a2175eb7579da880ae12ac DRTVWR-302 -f6ca5bb75bca975ff0bc77e71e615f6478c4559c 3.5.0-beta3 -910b5fad950e343b58229f5a0aefa7729b9308b3 DRTVWR-303 -53cffdde0b3cc367ba9bb6abd5c83ae14df5e882 3.5.0-beta4 -4d5f6234dc59a0fb6ead5e02c7d343a0610e0488 DRTVWR-304 -dd058a6093c493120d67c8e02c812c0f7b2d3db0 3.5.0-beta5 -fd6b510e83f56830e45670c428653134899d3e25 DRTVWR-305 -55339537d99afc394d1bb7fdb7d074bf321ca62f 3.5.0-beta6 -902caf2b9fdbdbc5c399c4d5ebcecaf9cb97bab8 DRTVWR-306 -5c6098fd17d40ee3a38ca6b64f6be9db7f61f0a8 3.5.0-beta7 -adc360e6bf21390d2665380951d85937cd29a604 3.5.0-release -1ada73295ed0eaa4a772ef079c29f57069342c32 DRTVWR-310 -20cdf370f5c8be6193bef6fb3a81cc3f81275191 3.5.1-beta1 -2319904200de367646b9a9442239a38d52c1eeb5 DRTVWR-313 -9d8726eca785acad694564516f16dd639faf45c0 3.5.1-beta2 -4b7fa963b80e2056ab648f83a4d61310b3cedb3d DRTVWR-314 -65ae89aeb7ea674a555e439e963f17949322ac94 3.5.1-beta3 -13149a524874b608aeb76325b35faff113a5ea53 3.5.1-release -78a8fe6abf331944d6b6bb1ce1024a6bc08141f4 DRTVWR-298 -50ccc12f38c3c99f03b374e32429cb043b73e2a6 DRTVWR-294 -c2b1066514308dff1eeb91162392dfe08bf1c0fe DRTVWR-309 -e6b8a92acffd693cd1459e4212e3dff1050acf67 DRTVWR-278 -106f19cc011aafdfc9a6d12b641fe8db6e9735a7 3.5.2-beta1 -509b97acc4ca1f2644197f1b555773ac0bb6838c 3.5.2-beta2 -6cb3689d89c13876ce8fa8faefa7b05e4279502d DRTVWR-316 -cfc3e650e5b2063288e7b832e9c9f521bbdacc92 DRTVWR-315 -e6e35501f1fea252ef83080adcf30c3cb7c2f75c DRTVWR-299 -b6a4ac8f1916ede76e8a023e1cf35c045d0ac707 3.5.2-beta3 -a314f1c94374ab1f6633dd2983f7090a68663eb2 3.5.2-beta4 -1cfa86d604909dfdb8b372069ff61f9afaa2aac1 MAINT-2647 -895628bb5e162410cfdf4bca58f0a57d22ccfcde 3.5.2-beta5 -9013c07bfe1c51107233f1924dccdcc5057dd909 3.5.2-beta6 -9b1b6f33aa5394b27bb652b31b5cb81ef6060370 3.5.2-release -a277b841729f2a62ba1e34acacc964bc13c1ad6f 3.5.3-release -fb1630153bac5552046ea914af3f14deabc1def8 3.6.0-materials-beta1 -0a56f33ad6aa112032b14a41dad759ad377bdde9 3.6.0-release -75cf8e855ae1af6895a35da475314c2b5acf1850 3.6.1-release -f6741d5fe8d632651424484df0fe0cb4a01e9fbe 3.6.2-release -fe4f7c5e9fd27e09d03deb1cc9ab3e5093f6309e 3.6.3-release -83357f31d8dbf048a8bfdc323f363bf4d588aca1 CHOP-951-a -91ed595b716f14f07409595b734fda891a59379e 3.6.4-release -bf6d453046011a11de2643fac610cc5258650f82 3.6.5-release -ae457ece77001767ae9613148c495e7b98cc0f4a 3.6.7-release -d40c66e410741de7e90b1ed6dac28dd8a2d7e1f6 3.6.8-release -70eda3721d36df3e00730629c42a1304e5bc65b8 3.6.9-release -5b54b36862ff8bc3b6935673c9d1c1f22ee8d521 3.6.10-release -2feb70a4cfde43f2898d95ff8fcae3e67805c7c2 3.6.11-release -88bbfd7a6971033f3aa103f3a3500ceb4c73521b 3.6.12-release -0d9b9e50f1a8880e05f15688a9ec7d09e0e81013 3.6.13-release -5d746de933a98ca17887cde2fece80e9c7ab0b98 3.7.0-release -dcb4981ce255841b6083d8f65444b65d5a733a17 3.7.1-release -b842534cb4d76c9ef87676a62b1d2d19e79c015f 3.7.2-release -962d3f98955bfc7310a7867c8cbc3df075e54aa9 3.7.3-release -d076568ff7883b41c149e6afb421f39c29dbfe2b 3.7.4-release -fc066b82343fca51f9c1b8eda0abc6bee9bb4503 3.7.5-release -d029faf69f20a23007f32420a1ac6a3b89a6d441 3.7.6-release -83959480cb986522d07b151a0c778ab7f920d41b 3.7.7-release -bba9b3722eea08949e4ff69591f736bf0f808434 3.7.8-release -a9f2d0cb11f73b06858e6083bb50083becc3f9cd 3.7.9-release -91dae9494b4d147541c7a01902334ba19a7ec05e 3.7.10-release -64799eb298834073a3e9992cd8d27c3cb9d30b10 3.7.11-release -3b44ea8988cb902f0dda8429e8d5e4569e304532 3.7.12-release -d86a7e1bc96d27b683f951d3701d5b7042158c68 3.7.13-release -a7872554f3665588f1e8347d472cec3a299254b3 3.7.14-release -3f11f57f2b4d15a9f987d12bc70ef507eefb5018 3.7.15-release -562e7dace7465060ac9adb2e8eca800b699ff024 3.7.16-release -bcc2770e21c125e0bab59141c51db9145aec068d 3.7.17-release -2729c1daf0257d68a40bdbc4acf1a16184974bbd 3.7.18-release -82973b38a6c9a457333e3519e4f2b16bb5eedf47 3.7.19-release -27094824773b907c2e559396e6f9ec3a963de52d 3.7.20-release -9ecab4b0c7d8614767724a3422d3c1dca6bd4e4f 3.7.21-release -bc61801f614022c920cb5c3df1d7d67a9561ce1f 3.7.22-release -3be800e1afad9615442159e388d6d137be7b951e 3.7.23-release -d3d0101e980ec95043e0af9b7903045d3bc447e4 3.7.24-release -9978a8c3a2ffce4a5e1c186256581c2ac139c9dc 3.7.25-release -000e9dda4162cbf0a83ba88558b19473654a09a9 3.7.26-release -afd8d4756e8eda3c8f760625d1c17a2ad40ad6c8 3.7.27-release -566874eb5ab26c003ef7fb0e22ce40c5fa0013f4 3.7.28-release -d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release -67edc442c80b8d2fadd2a6c4a7184b469906cdbf 3.7.30-release -797ed69e6134ef48bb922577ab2540fb2d964668 3.8.0-release -3f61ed662347dc7c6941b8266e72746a66d90e2a 3.8.1-release -3a62616f3dd8bd512fcdfd29ef033b2505b11213 3.8.2-release -60572f718879f786f6bc8b5c9373ebebf4693078 3.8.3-release -27e3cf444c4cc645884960a61325a9ee0e9a2d0f 3.8.4-release -e821ef17c6edea4a59997719d8ba416d8c16e143 3.8.5-release -5a5bd148943bfb46cf2ff2ccf376c42dee93d19b 3.8.6-release -ae3297cdd03ab14f19f3811acbc4acd3eb600336 4.0.0-release -759710a9acef61aaf7b69f4bc4a5a913de87ad8a 4.0.1-release -e9d350764dfbf5a46229e627547ef5c1b1eeef00 4.0.2-release -86dfba7ec4332c323025ebeacd8bf343ed0d8cfd 4.0.3-release -0a5de9ec2cb868f367501024d8d6958c20869053 4.0.4-release -450de775fff66a011be1a001acd117cc623c445d 4.0.5-release -4070611edd95eb3a683d1cd97c4c07fe67793812 4.0.6-release -33981d8130f031597b4c7f4c981b18359afb61a0 4.0.7-release -45eaee56883df7a439ed3300c44d3126f7e3a41e 4.0.8-release -b280a1c797a3891e68dbc237e73de9cf19f426e9 4.1.1-release -bfbba2244320dc2ae47758cd7edd8fa3b67dc756 4.1.2-release -b41e1e7c7876f7656c505f552b5888b4e478f92b 5.0.0-release -c9ce2295012995e3cf5c57bcffcb4870b94c649f 5.0.1-release -cea1632c002c065985ebea15eeeb4aac90f50545 5.0.2-release -02c24e9f4f7d8aa0de75f27817dda098582f4936 5.0.3-release -022709ef76a331cac1ba6ef1a6da8a5e9ef63f5a 5.0.4-release -b4d76b5590fdf8bab72c64442353753a527cbc44 5.0.5-release -3e5035dfd8af49bd4c0009f0a76ef46a15991a45 5.0.6-release -abcab37e1b29414ab8c03af9ca2ab489d809788a 5.0.7-release -505a492f30bd925bb48e2e093ae77c3c2b4c740f 5.0.8-release -40ca7118765be85a043b31b011e4ee6bd9e33c95 5.0.9-release -ad0e15543836d64d6399d28b32852510435e344a 5.1.0-release -26d9e9bb166a9a417f35b1863223a597af8185fd 5.1.1-release -2eb917875efdfe920680b9049302d0f03721245d 5.1.2-release -7c00e5b6cb3d95712e9d8e29277c805bca2bda90 5.1.3-release -7b6b020fd5ad9a8dc3670c5c92d1ca92e55fc485 5.1.4-release -2ea47f358b171178eb9a95503a1670d519c2886f 5.1.5-release -04538b8157c1f5cdacd9403f0a395452d4a93689 5.1.6-release -ac3b1332ad4f55b7182a8cbcc1254535a0069f75 5.1.7-release -23ea0fe36fadf009a60c080392ce80e4bf8af8d9 5.1.8-release -52422540bfe54b71155aa455360bee6e3ef1fd96 5.1.9-release -1cfa567caf5088ae299271be08cc2d9f0801ff6a pre-Poseidon -821edfcd14919c0e95c590866171c61fb57e8623 6.0.0-release -21b7604680ef6b6ea67f8bebaaa588d6e263bdc1 6.0.1-release -a3143db58a0f6b005232bf9018e7fef17ff9ec90 6.1.0-release -50f0ece62ddb5a244ecb6d00ef5a89d80ad50efa 6.1.1-release -82a89165e5929a6c3073d6cd60a543cb395f147b 6.2.0-release -706bdc7e25c6e6b8fb56f4a13fcce2936e70a79c 6.2.1-release -ec09daf1899c1c01c4ba0ba950fae572f2a612a8 6.2.2-release -ab2ec5c5423b277d23fd0511ce50c15123ff2e03 6.2.3-release -67297f9902857e357570c44722ad84de3aff974e 6.2.4-release -9777aec6dc4a30a24537297ac040861ce16b82ae 6.3.0-release -ece699718f163921717bb95a6131e94af4c4138f 6.3.1-release -07f5d5bc9faebb45695853d40a9549773db816c0 6.3.2-release -d9a4bd15e2c852953d6c8e84d6f3b7ca442c0e7f 6.3.3-release -4033b3f57e76f087235145a3016886ccdc87ffa3 6.3.4-release -27ca5834bfe9b80e82db5ea42f08b7eb990b722a 6.3.5-release diff --git a/autobuild.xml b/autobuild.xml index 57a2e82cfa320e215b2130dc7a0e935ff1bfdf03..d75b007d0e660a6ff6dcb79725d38f590cc8e180 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -758,9 +758,9 @@ <key>archive</key> <map> <key>hash</key> - <string>93257fce19120c01751362775a01b925</string> + <string>cba1feed7f6bb671d791a517fddf205a</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1545/3481/fmodex-4.44.64.501533-darwin64-501533.tar.bz2</string> + <string>https://downloads.catznip.com/packages/fmodex-44461-darwin-201601300040-r23.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -794,9 +794,9 @@ <key>archive</key> <map> <key>hash</key> - <string>601c2fc41a18812a45678ef9a87ef772</string> + <string>2038da4ab71da8dc086738007c0acdd3</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1546/3486/fmodex-4.44.64.501533-windows-501533.tar.bz2</string> + <string>http://viewer.catznip.com/downloads/packages/fmodex-4.44.61-windows-171261212.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -806,9 +806,9 @@ <key>archive</key> <map> <key>hash</key> - <string>e5cde35ae26ebfa256cfe670986e152e</string> + <string>b4b73cd64bfd72e7ae84aad429d69cf6</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1547/3487/fmodex-4.44.64.501533-windows64-501533.tar.bz2</string> + <string>http://viewer.catznip.com/downloads/packages/fmodex-4.44.61-windows64-171261211.tar.bz2</string> </map> <key>name</key> <string>windows64</string> @@ -2706,9 +2706,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>8a7f0be5647e07235d205ac00805fb78</string> + <string>545954e46a316e469f6b68ecbcb76573</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1116/2586/openjpeg-1.5.1.501102-windows-501102.tar.bz2</string> + <string>http://viewer.catznip.com/downloads/packages/openjpeg-1.5.2.171271050-windows-171271050.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2718,9 +2718,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>398544058036bc27097fcff208934d11</string> + <string>a68103651741c8b66356153ee5668d6b</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1115/2581/openjpeg-1.5.1.501102-windows64-501102.tar.bz2</string> + <string>http://viewer.catznip.com/downloads/packages/openjpeg-1.5.2.171271046-windows64-171271046.tar.bz2</string> </map> <key>name</key> <string>windows64</string> diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake index 720933d1b794bf369e17b70bd81591f1b79ff274..9753412de7b63f85d4f0c6c3837307e6ddbcade5 100644 --- a/indra/cmake/FMODEX.cmake +++ b/indra/cmake/FMODEX.cmake @@ -26,9 +26,15 @@ if (FMODEX) include(Prebuilt) use_prebuilt_binary(fmodex) if (WINDOWS) - set(FMODEX_LIBRARY - debug fmodexL_vc - optimized fmodex_vc) + if (ADDRESS_SIZE EQUAL 32) + set(FMODEX_LIBRARY + debug fmodexL_vc + optimized fmodex_vc) + else (ADDRESS_SIZE EQUAL 64) + set(FMODEX_LIBRARY + debug fmodexL64_vc + optimized fmodex64_vc) + endif (ADDRESS_SIZE EQUAL 32) elseif (DARWIN) set(FMODEX_LIBRARY debug fmodexL diff --git a/indra/cmake/FindWindowsSDK.cmake b/indra/cmake/FindWindowsSDK.cmake new file mode 100644 index 0000000000000000000000000000000000000000..32991ea66c9d6a7d47aafe7e45a00b5eccc99867 --- /dev/null +++ b/indra/cmake/FindWindowsSDK.cmake @@ -0,0 +1,631 @@ +# - Find the Windows SDK aka Platform SDK +# +# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK +# +# Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case +# you just want the tool binaries to run, rather than the libraries and headers +# for compiling. +# +# Variables: +# WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio +# WINDOWSSDK_LATEST_DIR +# WINDOWSSDK_LATEST_NAME +# WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version +# WINDOWSSDK_PREFERRED_DIR +# WINDOWSSDK_PREFERRED_NAME +# +# WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first. +# WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency +# +# Functions: +# windowssdk_name_lookup(<directory> <output variable>) - Find the name corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# +# windowssdk_build_lookup(<directory> <output variable>) - Find the build version number corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# +# get_windowssdk_from_component(<file or dir> <output variable>) - Given a library or include dir, +# find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized. +# +# get_windowssdk_library_dirs(<directory> <output variable>) - Find the architecture-appropriate +# library directories corresponding to the SDK directory you pass in (or NOTFOUND if none) +# +# get_windowssdk_library_dirs_multiple(<output variable> <directory> ...) - Find the architecture-appropriate +# library directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. +# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. +# +# get_windowssdk_include_dirs(<directory> <output variable>) - Find the +# include directories corresponding to the SDK directory you pass in (or NOTFOUND if none) +# +# get_windowssdk_include_dirs_multiple(<output variable> <directory> ...) - Find the +# include directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. +# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2012 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net> +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(_preferred_sdk_dirs) # pre-output +set(_win_sdk_dirs) # pre-output +set(_win_sdk_versanddirs) # pre-output +set(_win_sdk_buildsanddirs) # pre-output +set(_winsdk_vistaonly) # search parameters +set(_winsdk_kits) # search parameters + + +set(_WINDOWSSDK_ANNOUNCE OFF) +if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY)) + set(_WINDOWSSDK_ANNOUNCE ON) +endif() +macro(_winsdk_announce) + if(_WINSDK_ANNOUNCE) + message(STATUS ${ARGN}) + endif() +endmacro() + +set(_winsdk_win10vers + 10.0.18362.0 # 19H1 aka Win10 1809 "May 2019 Update" + 10.0.17763.0 # Redstone 5 aka Win10 1809 "October 2018 Update" + 10.0.17133.0 # Redstone 4 aka Win10 1803 "April 1018 Update" + 10.0.16299.0 # Redstone 3 aka Win10 1709 "Fall Creators Update" + 10.0.15063.0 # Redstone 2 aka Win10 1703 "Creators Update" + 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update" + 10.0.10586.0 # TH2 aka Win10 1511 + 10.0.10240.0 # Win10 RTM + 10.0.10150.0 # just ucrt + 10.0.10056.0 +) + +if(WindowsSDK_FIND_COMPONENTS MATCHES "tools") + set(_WINDOWSSDK_IGNOREMSVC ON) + _winsdk_announce("Checking for tools from Windows/Platform SDKs...") +else() + set(_WINDOWSSDK_IGNOREMSVC OFF) + _winsdk_announce("Checking for Windows/Platform SDKs...") +endif() + +# Appends to the three main pre-output lists used only if the path exists +# and is not already in the list. +function(_winsdk_conditional_append _vername _build _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_dirs "${_path}") + set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_versanddirs + "${_vername}" + "${_path}") + set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_buildsanddirs + "${_build}" + "${_path}") + set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE) +endfunction() + +# Appends to the "preferred SDK" lists only if the path exists +function(_winsdk_conditional_append_preferred _info _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + + get_filename_component(_path "${_path}" ABSOLUTE) + + list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_preferred_sdk_dirs "${_path}") + set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + + # Just in case we somehow missed it: + _winsdk_conditional_append("${_info}" "" "${_path}") +endfunction() + +# Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs". +# If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows +# and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits", +# use this macro first, since these registry keys usually have more information. +# +# Pass a "default" build number as an extra argument in case we can't find it. +function(_winsdk_check_microsoft_sdks_registry _winsdkver) + set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}") + get_filename_component(_sdkdir + "[${SDKKEY};InstallationFolder]" + ABSOLUTE) + + set(_sdkname "Windows SDK ${_winsdkver}") + + # Default build number passed as extra argument + set(_build ${ARGN}) + # See if the registry holds a Microsoft-mutilated, err, designated, product name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkproductname + "[${SDKKEY};ProductName]" + NAME) + if(NOT "${_sdkproductname}" MATCHES "registry") + # Got a product name + set(_sdkname "${_sdkname} (${_sdkproductname})") + endif() + + # try for a version to augment our name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkver + "[${SDKKEY};ProductVersion]" + NAME) + if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES) + # Got a version + if(NOT "${_sdkver}" MATCHES "\\.\\.") + # and it's not an invalid one with two dots in it: + # use to override the default build + set(_build ${_sdkver}) + if(NOT "${_sdkname}" MATCHES "${_sdkver}") + # Got a version that's not already in the name, let's use it to improve our name. + set(_sdkname "${_sdkname} (${_sdkver})") + endif() + endif() + endif() + _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes, the build number, and a key (technically a "value name") +# corresponding to a Windows SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Note that the key or "value name" tends to be something weird like KitsRoot81 - +# no easy way to predict, just have to observe them in the wild. +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]" + ABSOLUTE) + _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes and the build number +# corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_win10_kits _winkit_build) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" + ABSOLUTE) + if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}")) + return() # not found + endif() + if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um") + _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}") + endif() +endfunction() + +# Given a name for indentification purposes, the build number, and the associated package GUID, +# look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\ +# for that guid and the SDK it points to. +function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid) + foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER) + get_filename_component(_sdkdir + "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]" + ABSOLUTE) + _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}") + endforeach() +endfunction() + +### +# Detect toolchain information: to know whether it's OK to use Vista+ only SDKs +### +set(_winsdk_vistaonly_ok OFF) +if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC) + # VC 10 and older has broad target support + if(MSVC_VERSION LESS 1700) + # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+ + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp") + # This is the XP-compatible v110+ toolset + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90") + # This is the VS2010/VS2008 toolset + else() + # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset. + # These versions have no XP (and possibly Vista pre-SP1) support + set(_winsdk_vistaonly_ok ON) + if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED) + set(_WINDOWSSDK_VISTAONLY_PESTERED ON CACHE INTERNAL "" FORCE) + message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!") + endif() + endif() +endif() +if(_WINDOWSSDK_IGNOREMSVC) + set(_winsdk_vistaonly_ok ON) +endif() + +### +# MSVC version checks - keeps messy conditionals in one place +# (messy because of _WINDOWSSDK_IGNOREMSVC) +### +set(_winsdk_msvc_greater_1200 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200))) + set(_winsdk_msvc_greater_1200 ON) +endif() +# Newer than VS .NET/VS Toolkit 2003 +set(_winsdk_msvc_greater_1310 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310))) + set(_winsdk_msvc_greater_1310 ON) +endif() + +# VS2005/2008 +set(_winsdk_msvc_less_1600 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600))) + set(_winsdk_msvc_less_1600 ON) +endif() + +# VS2013+ +set(_winsdk_msvc_not_less_1800 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800))) + set(_winsdk_msvc_not_less_1800 ON) +endif() + +### +# START body of find module +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + ### + # Look for "preferred" SDKs + ### + + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() + + ### + # Begin the massive list of SDK searching! + ### + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # These require at least Visual Studio 2013 (VC12) + + _winsdk_check_microsoft_sdks_registry(v10.0A) + + # Windows Software Development Kit (SDK) for Windows 10 + # Several different versions living in the same directory - if nothing else we can assume RTM (10240) + _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0) + foreach(_win10build ${_winsdk_win10vers}) + _winsdk_check_win10_kits(${_win10build}) + endforeach() + endif() # vista-only and 2013+ + + # Included in Visual Studio 2013 + # Includes the v120_xp toolset + _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636) + + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # Windows Software Development Kit (SDK) for Windows 8.1 + # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891 + _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0) + _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81) + endif() # vista-only and 2013+ + + if(_winsdk_vistaonly_ok) + # Included in Visual Studio 2012 + _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727) + + # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5 + # This is the first version to also include the DirectX SDK + # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx + _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384) + _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot) + endif() # vista-only + + # Included with VS 2012 Update 1 or later + # Introduces v110_xp toolset + _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106) + if(_winsdk_vistaonly_ok) + # Microsoft Windows SDK for Windows 7 and .NET Framework 4 + # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b + _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514) + endif() # vista-only + + # Included with VS 2010 + _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385) + + # Windows SDK for Windows 7 and .NET Framework 3.5 SP1 + # Works with VC9 + # http://www.microsoft.com/en-us/download/details.aspx?id=18950 + _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385) + + # Two versions call themselves "v6.1": + # Older: + # Windows Vista Update & .NET 3.0 SDK + # http://www.microsoft.com/en-us/download/details.aspx?id=14477 + + # Newer: + # Windows Server 2008 & .NET 3.5 SDK + # may have broken VS9SP1? they recommend v7.0 instead, or a KB... + # http://www.microsoft.com/en-us/download/details.aspx?id=24826 + _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10) + + # Included in VS 2008 + _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1) + + # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components + # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx + _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384) +endif() + +# Let's not forget the Platform SDKs, which sometimes are useful! +if(_winsdk_msvc_greater_1200) + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1") + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3") +endif() +### +# Finally, look for "preferred" SDKs +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + + + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() +endif() + + +function(windowssdk_name_lookup _dir _outvar) + list(FIND _win_sdk_versanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_versanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +function(windowssdk_build_lookup _dir _outvar) + list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_buildsanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +# If we found something... +if(_win_sdk_dirs) + list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR) + windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}" + WINDOWSSDK_LATEST_NAME) + set(WINDOWSSDK_DIRS ${_win_sdk_dirs}) + + # Fallback, in case no preference found. + set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}") + set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}") + set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS}) + set(WINDOWSSDK_FOUND_PREFERENCE OFF) +endif() + +# If we found indications of a user preference... +if(_win_sdk_preferred_sdk_dirs) + list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR) + windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}" + WINDOWSSDK_PREFERRED_NAME) + set(WINDOWSSDK_PREFERRED_FIRST_DIRS + ${_win_sdk_preferred_sdk_dirs} + ${_win_sdk_dirs}) + list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS) + set(WINDOWSSDK_FOUND_PREFERENCE ON) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WindowsSDK + "No compatible version of the Windows SDK or Platform SDK found." + WINDOWSSDK_DIRS) + +if(WINDOWSSDK_FOUND) + # Internal: Architecture-appropriate library directory names. + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM") + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + # Only supported in Win10 SDK and up. + set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch arm) # what the architecture used to be called + set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture + endif() + else() + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch amd64) # what the architecture used to be called + set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch i386) # what the architecture used to be called + set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture + endif() + endif() + + function(get_windowssdk_from_component _component _var) + get_filename_component(_component "${_component}" ABSOLUTE) + file(TO_CMAKE_PATH "${_component}" _component) + foreach(_sdkdir ${WINDOWSSDK_DIRS}) + get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE) + string(LENGTH "${_sdkdir}" _sdklen) + file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}") + # If we don't have any "parent directory" items... + if(NOT "${_rel}" MATCHES "[.][.]") + set(${_var} "${_sdkdir}" PARENT_SCOPE) + return() + endif() + endforeach() + # Fail. + set(${_var} "NOTFOUND" PARENT_SCOPE) + endfunction() + function(get_windowssdk_library_dirs _winsdk_dir _var) + set(_dirs) + set(_suffixes + "lib${_winsdk_archbare}" # SDKs like 7.1A + "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir + "lib/w2k/${_winsdk_arch}" # Win2k min requirement + "lib/wxp/${_winsdk_arch}" # WinXP min requirement + "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement + "lib/wlh/${_winsdk_arch}" + "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement + "lib/win7/${_winsdk_arch}" + "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement + ) + foreach(_ver + wlh # Win Vista ("Long Horn") min requirement + win7 # Win 7 min requirement + win8 # Win 8 min requirement + winv6.3 # Win 8.1 min requirement + ) + + list(APPEND _suffixes + "lib/${_ver}/${_winsdk_arch}" + "lib/${_ver}/um/${_winsdk_arch8}" + "lib/${_ver}/km/${_winsdk_arch8}" + ) + endforeach() + + # Look for WDF libraries in Win10+ SDK + foreach(_mode umdf kmdf) + file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*") + if(_wdfdirs) + list(APPEND _suffixes ${_wdfdirs}) + endif() + endforeach() + + # Look in each Win10+ SDK version for the components + foreach(_win10ver ${_winsdk_win10vers}) + foreach(_component um km ucrt mmos) + list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) + # Check to see if a library actually exists here. + file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib") + if(_libs) + list(APPEND _dirs "${_winsdk_dir}/${_suffix}") + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() + function(get_windowssdk_include_dirs _winsdk_dir _var) + set(_dirs) + + set(_subdirs shared um winrt km wdf mmos ucrt) + set(_suffixes Include) + + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_dir}") + endforeach() + + foreach(_ver ${_winsdk_win10vers}) + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_ver}/${_dir}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) + # Check to see if a header file actually exists here. + file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h") + if(_headers) + list(APPEND _dirs "${_winsdk_dir}/${_suffix}") + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() + function(get_windowssdk_library_dirs_multiple _var) + set(_dirs) + foreach(_sdkdir ${ARGN}) + get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs) + if(_current_sdk_libdirs) + list(APPEND _dirs ${_current_sdk_libdirs}) + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() + function(get_windowssdk_include_dirs_multiple _var) + set(_dirs) + foreach(_sdkdir ${ARGN}) + get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs) + if(_current_sdk_libdirs) + list(APPEND _dirs ${_current_sdk_incdirs}) + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() +endif() \ No newline at end of file diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index a81c9307fc062c8ba18e168ad8779b0e47ab93ac..1f687f59dbea38fa11d14bb406318bc6a7a9dd8b 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -5,21 +5,30 @@ set(PYTHONINTERP_FOUND) if (WINDOWS) # On Windows, explicitly avoid Cygwin Python. - find_program(PYTHON_EXECUTABLE - NAMES python25.exe python23.exe python.exe - NO_DEFAULT_PATH # added so that cmake does not find cygwin python - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] - ) + if (DEFINED ENV{VIRTUAL_ENV}) + find_program(PYTHON_EXECUTABLE + NAMES python.exe + PATHS + "$ENV{VIRTUAL_ENV}\\scripts" + NO_DEFAULT_PATH + ) + else() + find_program(PYTHON_EXECUTABLE + NAMES python25.exe python23.exe python.exe + NO_DEFAULT_PATH # added so that cmake does not find cygwin python + PATHS + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] + ) + endif() elseif (EXISTS /etc/debian_version) # On Debian and Ubuntu, avoid Python 2.4 if possible. diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index a0418f09d50b21867074cb178057b4a7afb1f2d4..36409a6fb7d0b04fd184c99e34d81bc03f4d5874 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -52,6 +52,17 @@ LLControlGroup gSavedSettings("Global"); // saved at end of session LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +#include "llavatarname.h" + +// Stub for rlvGetAnonym +const std::string& rlvGetAnonym(const LLAvatarName& avName) +{ + static std::string strAnonym = "A resident"; + return strAnonym; +} +// [/RLVa:KB] + // We can't create LLImageGL objects because we have no window or rendering // context. Provide enough of an LLUIImage to test the LLUI library without // an underlying image. diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 2bf3b9085b813e75a2992ede703ab60b7502954a..c826e1ff2471a9b350635afdd387deac4cd87387 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -103,7 +103,15 @@ void LLWearableData::pushWearable(const LLWearableType::EType type, } if (canAddWearable(type)) { - mWearableDatas[type].push_back(wearable); +// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0) + // Don't add the same wearable twice + U32 idxWearable = 0; + if (!getWearableIndex(wearable, idxWearable)) + mWearableDatas[type].push_back(wearable); + else + llassert(false); // pushWearable() on an already added wearable is a bug *somewhere* +// [/RLVa:KB] +// mWearableDatas[type].push_back(wearable); mWearableDatas[type].push_back(wearable); if (trigger_updated) { const BOOL removed = FALSE; @@ -150,16 +158,16 @@ void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index) } } -void LLWearableData::clearWearableType(const LLWearableType::EType type) -{ - wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); - if (wearable_iter == mWearableDatas.end()) - { - return; - } - wearableentry_vec_t& wearable_vec = wearable_iter->second; - wearable_vec.clear(); -} +//void LLWearableData::clearWearableType(const LLWearableType::EType type) +//{ +// wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); +// if (wearable_iter == mWearableDatas.end()) +// { +// return; +// } +// wearableentry_vec_t& wearable_vec = wearable_iter->second; +// wearable_vec.clear(); +//} bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b) { diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index a0c446ea9e2bc6810ff85e8249c0251e0efd7e15..cb274ca52453932f86a5ae34768ccc5b396d539c 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -79,7 +79,7 @@ class LLWearableData virtual void wearableUpdated(LLWearable *wearable, BOOL removed); void eraseWearable(LLWearable *wearable); void eraseWearable(const LLWearableType::EType type, U32 index); - void clearWearableType(const LLWearableType::EType type); +// void clearWearableType(const LLWearableType::EType type); bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b); private: diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index dc02b5e2257b4e6e7bb27333c506fc8eda8a04ec..136786c109f668e35bd5eaf4dedd5b1dc49b3db2 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -60,6 +60,12 @@ class LLWearableDictionary : public LLSingleton<LLWearableDictionary>, public LLDictionary<LLWearableType::EType, WearableEntry> { LLSINGLETON(LLWearableDictionary); + +// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +protected: + // The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType + virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; } +// [/RLVa:KB] }; LLWearableDictionary::LLWearableDictionary() @@ -87,7 +93,10 @@ LLWearableDictionary::LLWearableDictionary() addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry("universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE)); - addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6) + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE)); +// [/SL:KB] +// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE)); addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 0174c411b4bfa062f0450817082df67d21b41cad..08551a39555e2ae1426ea168948a664c220d6d8a 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -577,6 +577,78 @@ std::string utf8str_truncate(const std::string& utf8str, const S32 max_len) } } +// [RLVa:KB] - Checked: RLVa-2.1.0 +std::string utf8str_substr(const std::string& utf8str, const S32 index, const S32 max_len) +{ + if (0 == max_len) + { + return std::string(); + } + if (utf8str.length() - index <= max_len) + { + return utf8str.substr(index, max_len); + } + else + { + S32 cur_char = max_len; + + // If we're ASCII, we don't need to do anything + if ((U8)utf8str[index + cur_char] > 0x7f) + { + // If first two bits are (10), it's the tail end of a multibyte char. We need to shift back + // to the first character + while (0x80 == (0xc0 & utf8str[index + cur_char])) + { + cur_char--; + // Keep moving forward until we hit the first char; + if (cur_char == 0) + { + // Make sure we don't trash memory if we've got a bogus string. + break; + } + } + } + // The byte index we're on is one we want to get rid of, so we only want to copy up to (cur_char-1) chars + return utf8str.substr(index, cur_char); + } +} + +void utf8str_split(std::list<std::string>& split_list, const std::string& utf8str, size_t maxlen, char split_token) +{ + split_list.clear(); + + std::string::size_type lenMsg = utf8str.length(), lenIt = 0; + + const char* pstrIt = utf8str.c_str(); std::string strTemp; + while (lenIt < lenMsg) + { + if (lenIt + maxlen < lenMsg) + { + // Find the last split character + const char* pstrTemp = pstrIt + maxlen; + while ( (pstrTemp > pstrIt) && (*pstrTemp != split_token) ) + pstrTemp--; + + if (pstrTemp > pstrIt) + strTemp = utf8str.substr(lenIt, pstrTemp - pstrIt); + else + strTemp = utf8str_substr(utf8str, lenIt, maxlen); + } + else + { + strTemp = utf8str.substr(lenIt, std::string::npos); + } + + split_list.push_back(strTemp); + + lenIt += strTemp.length(); + pstrIt = utf8str.c_str() + lenIt; + if (*pstrIt == split_token) + lenIt++; + } +} +// [/RLVa:KB] + std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len) { if (0 == symbol_len) diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index b619a9e48c55796693f4937797ff36f3cc64cc19..dd0ed69237ebaf27086bc1cc006f1e7e69abb69d 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -36,6 +36,9 @@ #include <vector> #include <map> #include "llformat.h" +// [RLVa:KB] - Checked: RLVa-2.1.0 +#include <list> +// [/RLVa:KB] #if LL_LINUX || LL_SOLARIS #include <wctype.h> @@ -664,6 +667,11 @@ LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wst */ LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); +// [RLVa:KB] - Checked: RLVa-2.1.0 +LL_COMMON_API std::string utf8str_substr(const std::string& utf8str, const S32 index, const S32 max_len); +LL_COMMON_API void utf8str_split(std::list<std::string>& split_list, const std::string& utf8str, size_t maxlen, char split_token); +// [/RLVa:KB] + LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); LL_COMMON_API S32 utf8str_compare_insensitive( diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 3b1b060c023b4ffe4146bcb8f972bf20644d5852..eaccd62462b2f73bf1285096f3c6160f0e72bfd0 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -386,7 +386,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo ) { self->setLastError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )"); LLTHROW(LLContinueError("Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )")); - return false; +// return false; } memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize ); /* Flawfinder: ignore */ delete[] self->mOutputBuffer; diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index a8768bda35ea1060b09f3ca95ae6948a6d602399..1f3d9b7d218c099e76052d0f15c3a2b89dc47ea6 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -59,6 +59,9 @@ LLColor4 LLColor4::grey1(0.8f, 0.8f, 0.8f, 1.0f); LLColor4 LLColor4::grey2(0.6f, 0.6f, 0.6f, 1.0f); LLColor4 LLColor4::grey3(0.4f, 0.4f, 0.4f, 1.0f); LLColor4 LLColor4::grey4(0.3f, 0.3f, 0.3f, 1.0f); +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) +LLColor4 LLColor4::silhouette(0.05f, 0.05f, 0.05f, 1.0f); +// [/RLVa:KB] LLColor4 LLColor4::red1(1.0f, 0.0f, 0.0f, 1.0f); LLColor4 LLColor4::red2(0.6f, 0.0f, 0.0f, 1.0f); diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 8f353ead5a251c95aca64570f66329753868f7d3..32e82a743ea84ffd7f8ac02e7b39b22bef0bc3f9 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -154,6 +154,9 @@ class LLColor4 static LLColor4 grey2; static LLColor4 grey3; static LLColor4 grey4; +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + static LLColor4 silhouette; +// [/RLVa:KB] static LLColor4 red1; static LLColor4 red2; diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 6a287f0cc5cf43b87145f482d3339a53f31aac60..1071ac87e71c738c9fdca783c20ec4601e362372 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -49,7 +49,6 @@ #include <map> #include <set> - // Time-to-live for a temp cache entry. const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; // Maximum time an unrefreshed cache entry is allowed. @@ -680,10 +679,30 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(cons return connection; } +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c +bool LLAvatarNameCache::getForceDisplayNames() +{ + return mRlvForceDisplayNames; +} + +void LLAvatarNameCache::setForceDisplayNames(bool force) +{ + mRlvForceDisplayNames = force; + if ( (!LLAvatarName::useDisplayNames()) && (force) ) + { + LLAvatarName::setUseDisplayNames(true); + } +} +// [/RLVa:KB] void LLAvatarNameCache::setUseDisplayNames(bool use) { +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c + // We need to force the use of the "display names" cache when @shownames=n restricted (and disallow toggling it) + use |= getForceDisplayNames(); +// [/RLVa:KB] if (use != LLAvatarName::useDisplayNames()) + { LLAvatarName::setUseDisplayNames(use); mUseDisplayNamesSignal(); diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index ba89d569f3f6f9ce1315a151d070861df2db1f0d..6a4f73a6eb9ef0c21754e7e62aaa0dd1aeacfe27 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -84,6 +84,12 @@ class LLAvatarNameCache : public LLSingleton<LLAvatarNameCache> void setUseUsernames(bool use); void insert(const LLUUID& agent_id, const LLAvatarName& av_name); + +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c + bool getForceDisplayNames(); + void setForceDisplayNames(bool force); +// [/RLVa:KB] + void erase(const LLUUID& agent_id); // A way to find agent id by UUID, very slow, also unreliable @@ -150,6 +156,11 @@ class LLAvatarNameCache : public LLSingleton<LLAvatarNameCache> // For testing, there's a UsePeopleAPI setting that can be flipped (must restart viewer). bool mUsePeopleAPI; +// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c + // RLVa override for display names + bool mRlvForceDisplayNames = false; +// [/RLVa:KB] + // Base lookup URL for name service. // On simulator, loaded from indra.xml // On viewer, usually a simulator capability (at People API team's request) diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index 3a6eebebbafef5b399376fce6dc1e16fa6c25f83..5676001fdfdbec698ec8fd77b71abbf80007d5fc 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -316,7 +316,10 @@ BOOL LLGLTexture::getIsAlphaMask() const return mGLTexturep->getIsAlphaMask() ; } -BOOL LLGLTexture::getMask(const LLVector2 &tc) +//BOOL LLGLTexture::getMask(const LLVector2 &tc) +// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) +bool LLGLTexture::getMask(const LLVector2 &tc) const +// [/RLVa:KB] { llassert(mGLTexturep.notNull()) ; diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 70610d96264dd94e548e1bf1e6d604640d2aa5d0..59fc3139c7cf3b13b602168500bd4be9cf89b724 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -143,7 +143,10 @@ class LLGLTexture : public LLTexture LLGLenum getPrimaryFormat() const; BOOL getIsAlphaMask() const ; LLTexUnit::eTextureType getTarget(void) const ; - BOOL getMask(const LLVector2 &tc); +// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) + bool getMask(const LLVector2 &tc) const; +// [/RLVa:KB] +// BOOL getMask(const LLVector2 &tc); F32 getTimePassedSinceLastBound(); BOOL getMissed() const ; BOOL isJustBound()const ; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 40217b2e80ee017d44d16c9760c8032fffd0ffc1..fffaa4600774a5461e0c10ddc9890abb4f03acf3 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2003,7 +2003,10 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) } } -BOOL LLImageGL::getMask(const LLVector2 &tc) +//BOOL LLImageGL::getMask(const LLVector2 &tc) +// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) +BOOL LLImageGL::getMask(const LLVector2 &tc) const +// [/RLVa:KB] { BOOL res = TRUE; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 2be54be062a9ef0f892b734b239b0238683ed44e..740c08aa776c74b5f8e40cbe2223ac7d78f793ad 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -150,7 +150,10 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL> void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } void updatePickMask(S32 width, S32 height, const U8* data_in); - BOOL getMask(const LLVector2 &tc); +// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) + BOOL getMask(const LLVector2 &tc) const; +// [/RLVa:KB] +// BOOL getMask(const LLVector2 &tc); void checkTexSize(bool forced = false) const ; diff --git a/indra/llui/llchat.h b/indra/llui/llchat.h index f5b242fdfcddabbbba473dff6b405ad63103d35c..746103b9115590a9cc9400931457848ee79f57f1 100644 --- a/indra/llui/llchat.h +++ b/indra/llui/llchat.h @@ -81,6 +81,10 @@ class LLChat mChatType(CHAT_TYPE_NORMAL), mAudible(CHAT_AUDIBLE_FULLY), mMuted(FALSE), +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a + mRlvLocFiltered(FALSE), + mRlvNamesFiltered(FALSE), +// [/RLVa:KB] mTime(0.0), mTimeStr(), mPosAgent(), @@ -98,6 +102,10 @@ class LLChat EChatType mChatType; EChatAudible mAudible; BOOL mMuted; // pass muted chat to maintain list of chatters +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a + BOOL mRlvLocFiltered; + BOOL mRlvNamesFiltered; +// [/RLVa:KB] F64 mTime; // viewer only, seconds from viewer start std::string mTimeStr; LLVector3 mPosAgent; diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 230ea200d888545ecee96e0a52f30f1fa68e6487..6bcc94fe47f473f3d7f5a59fd4ba7565697e7508 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -471,6 +471,9 @@ class LLFlatListViewEx : public LLFlatListView // *WORKAROUND: two methods to overload appropriate Params due to localization issue: // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 +// [RLVa:KB] - Checked: RLVa-2.0.3 + const std::string& getNoItemsMsg() const { return mNoItemsMsg; } +// [/RLVa:KB] void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index 85e07fc6a6a0f2a3dd2a41c61e4bae891db5422b..b7dea9439760b1a355a989740573b7cef40d4451 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -45,6 +45,10 @@ std::set<std::string> LLFloaterReg::sAlwaysShowableList; static LLFloaterRegListener sFloaterRegListener; +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a +LLFloaterReg::validate_signal_t LLFloaterReg::mValidateSignal; +// [/RLVa:KB] + //******************************************************* //static @@ -240,12 +244,23 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str // Visibility Management +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +//static +bool LLFloaterReg::canShowInstance(const std::string& name, const LLSD& key) +{ + return mValidateSignal(name, key); +} +// [/RLVa:KB] + //static LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) { - if( sBlockShowFloaters - // see EXT-7090 - && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) +// if( sBlockShowFloaters +// // see EXT-7090 +// && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a + if ( (sBlockShowFloaters && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) || (!mValidateSignal(name, key)) ) +// [/RLVa:KB] return 0;// LLFloater* instance = getInstance(name, key); if (instance) diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index e3b17dcb4fc7507e8846984b61027732275bb0f4..5bafe6466473634237af880d650eb3e1e85e5a8a 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -32,6 +32,10 @@ #include <list> #include <boost/function.hpp> +// [RLVa:KB] - Checked: 2011-05-25 (RLVa-1.4.0a) +#include <boost/signals2.hpp> +#include "llboost.h" +// [/RLVa:KB] //******************************************************* // @@ -72,6 +76,15 @@ class LLFloaterReg */ static std::set<std::string> sAlwaysShowableList; +// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a + // Used to determine whether a floater can be shown +public: + typedef boost::signals2::signal<bool(const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t; + static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); } +private: + static validate_signal_t mValidateSignal; +// [/RLVa:KB] + public: // Registration @@ -100,6 +113,10 @@ class LLFloaterReg static const_instance_list_t& getFloaterList(const std::string& name); // Visibility Management +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + // return false if floater can not be shown (=doesn't pass the validation filter) + static bool canShowInstance(const std::string& name, const LLSD& key = LLSD()); +// [/RLVa:KB] // return NULL if instance not found or can't create instance (no builder) static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE); // Close a floater (may destroy or set invisible) diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 6a7075301bea873a472c71d21fb0538d79ae1d49..4446a6e7f425701153d9651c4e5da31c015a217b 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -927,6 +927,13 @@ std::string LLNotification::getLabel() const return (mTemplatep ? label : ""); } +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a +bool LLNotification::hasLabel() const +{ + return !mTemplatep->mLabel.empty(); +} +// [/SL:KB] + std::string LLNotification::getURL() const { if (!mTemplatep) diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 62cf41256bfd3984837f2ab7252114fd3df77158..269d1c7fa5438733a2f65150a8fbbfb18714e268 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -536,6 +536,10 @@ friend class LLNotifications; return mTimestamp; } +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + bool hasLabel() const; +// [/SL:KB] + bool getOfferFromAgent() const { return mOfferFromAgent; diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index e6f466ec784b9f1c5dbf90ede4a64d17dfd6f820..47bfdae0a0e185ced43e5e2dcd3f9c0021e16763 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1221,6 +1221,9 @@ void LLToolBarButton::setEnabled(BOOL enabled) mImageOverlayColor = mImageOverlayDisabledColor; mImageOverlaySelectedColor = mImageOverlayDisabledColor; } +// [RLVa:KB] - Checked: 2011-12-17 (RLVa-1.4.5a) | Added: RLVa-1.4.5a + LLButton::setEnabled(enabled); +// [/RLVa:KB] } const std::string LLToolBarButton::getToolTip() const diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 656b69d3ed50ba0d3d9876a23afff9d3fbe94431..121e8c6374c35106bd1ee0a98408b612f9c0d329 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -191,6 +191,9 @@ mHelpImpl(NULL) // Used by menus along with Floater.Toggle to display visibility as a check-mark LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.Visible", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.IsOpen", boost::bind(&LLFloaterReg::instanceVisible, _2, LLSD())); +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.CanShow", boost::bind(&LLFloaterReg::canShowInstance, _2, LLSD())); +// [/RLVa:KB] // Parse the master list of commands LLCommandManager::load(); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 333d03f208da6ee44e86357946d133f40c534163..7178f2fc5b9fca4530eb3ba7166ed3f0d9bea003 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -817,6 +817,27 @@ std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name) return avatar_name.getAccountName(); } +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + +// Defined in rlvcommon.cpp - redirects to RlvStrings::getAnonym() since we can't really get to that class from here +extern const std::string& rlvGetAnonym(const LLAvatarName& avName); + +// +// LLUrlEntryAgentRLVAnonymizedName Describes an RLV anonymized agent name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym +// +LLUrlEntryAgentRLVAnonymizedName::LLUrlEntryAgentRLVAnonymizedName() +{ + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/rlvanonym", boost::regex::perl|boost::regex::icase); +} + +std::string LLUrlEntryAgentRLVAnonymizedName::getName(const LLAvatarName& avatar_name) +{ + return rlvGetAnonym(avatar_name); +} +// [/RLVa:KB] + // // LLUrlEntryGroup Describes a Second Life group Url, e.g., // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 78c149d9fde18918d952ad81ffce44a60c43882c..baa2ac651f79e08f024612310b96f71c6021fdc5 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -304,6 +304,21 @@ class LLUrlEntryAgentUserName : public LLUrlEntryAgentName /*virtual*/ std::string getName(const LLAvatarName& avatar_name); }; +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +/// +/// LLUrlEntryAgentRLVAnonymizedName Describes an RLV anonymized agent name Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/rlvanonym +/// that diplays an anonym (based on the display name) for an avatar +/// such as "An individual" +class LLUrlEntryAgentRLVAnonymizedName : public LLUrlEntryAgentName +{ +public: + LLUrlEntryAgentRLVAnonymizedName(); +private: + /*virtual*/ std::string getName(const LLAvatarName& avatar_name); +}; +// [/RLVa:KB] + /// /// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g., /// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index ba6fa1e2e9586d596a21fae09b4664683fdf72e2..b526c1df085bb585d9125ddd7057eebaff7c6dd6 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -38,7 +38,10 @@ void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, LLUrlRegistry::LLUrlRegistry() { - mUrlEntry.reserve(20); +// mUrlEntry.reserve(20); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + mUrlEntry.reserve(21); +// [/RLVa:KB] // Urls are matched in the order that they were registered mUrlEntryNoLink = new LLUrlEntryNoLink(); @@ -60,6 +63,9 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryAgentLegacyName()); registerUrl(new LLUrlEntryAgentDisplayName()); registerUrl(new LLUrlEntryAgentUserName()); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + registerUrl(new LLUrlEntryAgentRLVAnonymizedName()); +// [/RLVa:KB] // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since // LLUrlEntryAgent is a less specific (catchall for agent urls) registerUrl(new LLUrlEntryAgent()); diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index 338be1808dd84d174d0293c15a93e8c740f9f944..36aa316696e698459b36af0ff797efe6a1fc34c3 100755 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -35,6 +35,15 @@ #include <string> +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +// Stub for rlvGetAnonym +const std::string& rlvGetAnonym(const LLAvatarName& avName) +{ + static std::string strAnonym = "A resident"; + return strAnonym; +} +// [/RLVa:KB] + // Stub for LLAvatarNameCache bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) { diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index de0d366492fcf475d60695955d8976e975fdd54a..b68187e196b50430a94fe2965c5723bfff05baa9 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -134,6 +134,9 @@ class LLControlVariable : public LLRefCount commit_signal_t* getCommitSignal() { return &mCommitSignal; } validate_signal_t* getValidateSignal() { return &mValidateSignal; } +// [RLVa:KB] - Patch: RLVa-2.1.0 + bool hasUnsavedValue() { return mValues.size() > 2; } +// [/RLVa:KB] bool isDefault() { return (mValues.size() == 1); } bool shouldSave(bool nondefault_only); bool isPersisted() { return mPersist != PERSIST_NO; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7c8bf34590add01fd307c6e9e544d3362e7bb005..d215439cda2e5380c1008777c280a5b909198bc8 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -722,6 +722,16 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp pipeline.cpp + rlvactions.cpp + rlvhandler.cpp + rlvhelper.cpp + rlvcommon.cpp + rlvlocks.cpp + rlvinventory.cpp + rlvextensions.cpp + rlvfloaters.cpp + rlvmodifiers.cpp + rlvui.cpp ) set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING @@ -1340,6 +1350,17 @@ set(viewer_HEADER_FILES macmain.h noise.h pipeline.h + rlvactions.h + rlvdefines.h + rlvhandler.h + rlvhelper.h + rlvcommon.h + rlvlocks.h + rlvinventory.h + rlvextensions.h + rlvfloaters.h + rlvmodifiers.h + rlvui.h roles_constants.h VertexCache.h VorbisFramework.h @@ -1744,7 +1765,7 @@ if (WINDOWS) # *TODO -reenable this once we get server usage sorted out LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE" LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO /LARGEADDRESSAWARE" - LINK_FLAGS_RELEASE "/FORCE:MULTIPLE /MAP\"secondlife-bin.MAP\" /OPT:REF /LARGEADDRESSAWARE" + LINK_FLAGS_RELEASE "/MAP\"secondlife-bin.MAP\" /OPT:REF /LARGEADDRESSAWARE" ) if(USE_PRECOMPILED_HEADERS) @@ -1867,6 +1888,21 @@ if (WINDOWS) windows-crash-logger ) + # sets the 'working directory' for debugging from visual studio. + if (NOT UNATTENDED) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/tools/vstool/vstool.exe + ARGS + --solution + ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.sln + --workingdir + ${VIEWER_BINARY_NAME} + "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Setting the ${VIEWER_BINARY_NAME} working directory for debugging." + ) + endif (NOT UNATTENDED) + # sets the 'working directory' for debugging from visual studio. # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865) if (NOT UNATTENDED) diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 98143bbce61353b4275cec36ad8a5121e5af5c30..3d6b40c59c1db3f2dac0cc3f928ceafd4cf5e348 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -7,6 +7,8 @@ tooltip_ref="Command_AboutLand_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="about_land" + is_enabled_function="Floater.CanShow" + is_enabled_parameters="about_land" is_running_function="Floater.IsOpen" is_running_parameters="about_land" /> @@ -98,6 +100,8 @@ tooltip_ref="Command_Inventory_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="inventory" + is_enabled_function="RLV.EnableIfNot" + is_enabled_parameters="showinv" is_running_function="Floater.IsOpen" is_running_parameters="inventory" /> @@ -108,6 +112,8 @@ tooltip_ref="Command_Map_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="world_map" + is_enabled_function="RLV.EnableIfNot" + is_enabled_parameters="showworldmap" is_running_function="Floater.IsOpen" is_running_parameters="world_map" /> @@ -137,6 +143,8 @@ tooltip_ref="Command_MiniMap_Tooltip" execute_function="Floater.ToggleOrBringToFront" execute_parameters="mini_map" + is_enabled_function="RLV.EnableIfNot" + is_enabled_parameters="showminimap" is_running_function="Floater.IsOpen" is_running_parameters="mini_map" /> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index da1e87fda47b5e2c69df73332707e1fb34a1d16d..fa897a37d9f7b210cf265ac75bb7a4339cc3913a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2,6 +2,292 @@ <llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> <map> + <key>RestrainedLove</key> + <map> + <key>Comment</key> + <string>Toggles RLVa features (requires restart)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RestrainedLoveDebug</key> + <map> + <key>Comment</key> + <string>Toggles RLVa debug mode (displays the commands when in debug mode)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RestrainedLoveCanOOC</key> + <map> + <key>Comment</key> + <string>Allows sending OOC chat when send chat restricted, or seeing OOC chat when receive chat restricted</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RestrainedLoveForbidGiveToRLV</key> + <map> + <key>Comment</key> + <string>When TRUE, forbids to give sub-folders to the #RLV folder</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RestrainedLoveNoSetEnv</key> + <map> + <key>Comment</key> + <string>When TRUE, forbids to set the environment (time of day and Windlight settings) via RLVa. (requires restart)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RestrainedLoveReplaceWhenFolderBeginsWith</key> + <map> + <key>Comment</key> + <string>If a folder name begins with this string, its attach behavior will always be "replace", never "stack". Default is blank (disabled).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> + <key>RestrainedLoveShowEllipsis</key> + <map> + <key>Comment</key> + <string>When TRUE, show "..." when someone speaks, while the avatar is prevented from hearing. When FALSE, don't show anything.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RestrainedLoveStackWhenFolderBeginsWith</key> + <map> + <key>Comment</key> + <string>If a folder name begins with this string, its attach behavior will always be "stack", never "replace". Default is "+".</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>+</string> + </map> + <key>RLVaBlockedExperiences</key> + <map> + <key>Comment</key> + <string>List of experiences blocked from interacting with RLVa</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>bfe25fb4-222c-11e5-85a2-fa4c4ccaa202</string> + </map> + <key>RLVaCompatibilityModeList</key> + <map> + <key>Comment</key> + <string>Contains a list of creators or partial items names that require compatibility mode handling (see wiki for more information and syntax)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string></string> + </map> + <key>RLVaDebugDeprecateExplicitPoint</key> + <map> + <key>Comment</key> + <string>Ignore attachment point names on inventory items and categories (incomplete)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaDebugHideUnsetDuplicate</key> + <map> + <key>Comment</key> + <string>Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaEnableCompositeFolders</key> + <map> + <key>Comment</key> + <string>Enables composite folders for shared inventory</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaEnableIMQuery</key> + <map> + <key>Comment</key> + <string>Enables a limited number of configuration queries via IM (e.g. @version)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaEnableLegacyNaming</key> + <map> + <key>Comment</key> + <string>Enables legacy naming convention for folders</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaEnableSharedWear</key> + <map> + <key>Comment</key> + <string>Attachments in the shared #RLV folder can be force-attached without needing to specify an attachment point</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaEnableTemporaryAttachments</key> + <map> + <key>Comment</key> + <string>Allows temporary attachments (regardless of origin) to issue RLV commands</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaExperimentalCommands</key> + <map> + <key>Comment</key> + <string>Enables the experimental command set</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaExperienceMaturityThreshold</key> + <map> + <key>Comment</key> + <string>Specifies the minimum maturity an experience has to be before it can interact with RLVa (0: never; 1: PG; 2: Mature; 3: Adult)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>2</integer> + </map> + <key>RLVaHideLockedLayers</key> + <map> + <key>Comment</key> + <string>Hides "remove outfit" restricted worn clothing layers from @getoufit</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaHideLockedAttachments</key> + <map> + <key>Comment</key> + <string>Hides non-detachable worn attachments from @getattach</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaSharedInvAutoRename</key> + <map> + <key>Comment</key> + <string>Automatically renames shared inventory items when worn</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaShowAssertionFailures</key> + <map> + <key>Comment</key> + <string>Notify the user when an assertion fails</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaSplitRedirectChat</key> + <map> + <key>Comment</key> + <string>Splits long nearby chat lines across multiple messages when @redir* restricted.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>0</boolean> + </map> + <key>RLVaTopLevelMenu</key> + <map> + <key>Comment</key> + <string>Show the RLVa specific menu as a top level menu</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> + <key>RLVaWearReplaceUnlocked</key> + <map> + <key>Comment</key> + <string>Don't block wear replace when at least one attachment on the target attachment point is non-detachable</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> <key>ImporterDebug</key> <map> <key>Comment</key> @@ -159,6 +445,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>AISCommandFilterMask</key> + <map> + <key>Comment</key> + <string>AIS command filter (death by Kitty if you change this)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>65247</integer> + </map> <key>AlertedUnsupportedHardware</key> <map> <key>Comment</key> @@ -878,6 +1175,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>BlockAttachmentKillsOnTeleport</key> + <map> + <key>Comment</key> + <string>Ignore all attachment object kills during teleport</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> <key>BlockAvatarAppearanceMessages</key> <map> <key>Comment</key> @@ -4459,6 +4767,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>ForceMissingType</key> + <map> + <key>Comment</key> + <string>Force this wearable type to be missing from COF</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>255</integer> + </map> <key>FreezeTime</key> <map> <key>Comment</key> @@ -6991,6 +7310,17 @@ <key>Value</key> <integer>305</integer> </map> + <key>NotificationCanEmbedInIM</key> + <map> + <key>Comment</key> + <string>Controls notification panel embedding in IMs (0 = default, 1 = focused, 2 = never)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>0</integer> + </map> <key>NotificationConferenceIMOptions</key> <map> <key>Comment</key> @@ -10112,6 +10442,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RenderResolutionMultiplier</key> + <map> + <key>Comment</key> + <string>Multiplier for rendering 3D scene at reduced resolution.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> <key>RenderShaderLightingMaxLevel</key> <map> <key>Comment</key> @@ -11459,7 +11800,7 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <boolean>1</boolean> </map> <key>NearbyListShowIcons</key> <map> diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 8f4ca6c6337e47bde432c347c251079a8d657a97..358abc7786a852b2b896761a5ad0e2b89c201c28 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -1,5 +1,18 @@ <llsd> <map> + <key>RLVaLoginLastLocation</key> + <map> + <key>Comment</key> + <string>Determines whether the next login will be forced to the last logoff location (set by RLVa)</string> + <key>Persist</key> + <integer>1</integer> + <key>HideFromEditor</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <boolean>1</boolean> + </map> <key>AvatarHoverOffsetZ</key> <map> <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 31b8b9051887cc0c1984709a23ae772d1fbeefae..1503d6ffe49a33dca4f0dcb149f417f06dde5fea 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -96,6 +96,12 @@ #include "stringize.h" #include "boost/foreach.hpp" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvui.h" +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -205,7 +211,10 @@ class LLTeleportRequestViaLocation : public LLTeleportRequest class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation { public: - LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); +// [RLVa:KB] - Checked: RLVa-2.0.0 + LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal, const LLVector3& look_at); +// [/RLVa:KB] +// LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocationLookAt(); virtual bool canRestartTeleport(); @@ -214,8 +223,14 @@ class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation virtual void restartTeleport(); protected: +// [RLVa:KB] - Checked: RLVa-2.0.0 + const LLVector3& getLookAt() const { return mLookAt; } +// [/RLVa:KB] private: +// [RLVa:KB] - Checked: RLVa-2.0.0 + LLVector3 mLookAt; +// [/RLVa:KB] }; @@ -359,7 +374,10 @@ LLAgent::LLAgent() : mDoubleTapRunMode(DOUBLETAP_NONE), mbAlwaysRun(false), - mbRunning(false), +// mbRunning(false), +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + mbTempRun(false), +// [/RLVa:KB] mbTeleportKeepsLookAt(false), mAgentAccess(new LLAgentAccess(gSavedSettings)), @@ -528,11 +546,11 @@ LLAgent::~LLAgent() //----------------------------------------------------------------------------- void LLAgent::onAppFocusGained() { - if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode()) - { - gAgentCamera.changeCameraToDefault(); - LLToolMgr::getInstance()->clearSavedTool(); - } +// if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode()) +// { +// gAgentCamera.changeCameraToDefault(); +// LLToolMgr::getInstance()->clearSavedTool(); +// } } @@ -655,6 +673,13 @@ void LLAgent::moveLeftNudge(S32 direction) //----------------------------------------------------------------------------- void LLAgent::moveUp(S32 direction) { +// [RLVa:KB] - Checked: RLVa-2.2 (@jump) + if ( (!RlvActions::canJump()) && (direction > 0) && (!getFlying()) ) + { + return; + } +// [/Sl:KB] + mMoveTimer.reset(); LLFirstUse::notMoving(false); @@ -718,6 +743,12 @@ void LLAgent::movePitch(F32 mag) // Does this parcel allow you to fly? BOOL LLAgent::canFly() { +// [RLVa:KB] - Checked: RLVa-1.0 + if (!RlvActions::canFly()) + { + return FALSE; + } +// [/RLVa:KB] if (isGodlike()) return TRUE; LLViewerRegion* regionp = getRegion(); @@ -766,6 +797,13 @@ void LLAgent::setFlying(BOOL fly, BOOL fail_sound) if (fly) { +// [RLVa:KB] - Checked: RLVa-1.0 + if (!RlvActions::canFly()) + { + return; + } +// [/RLVa:KB] + BOOL was_flying = getFlying(); if (!canFly() && !was_flying) { @@ -831,7 +869,14 @@ bool LLAgent::enableFlying() void LLAgent::standUp() { - setControlFlags(AGENT_CONTROL_STAND_UP); +// setControlFlags(AGENT_CONTROL_STAND_UP); +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking + if ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) ) + { + setControlFlags(AGENT_CONTROL_STAND_UP); + } +// [/RLVa:KB] } void LLAgent::changeParcels() @@ -937,7 +982,10 @@ void LLAgent::setRegion(LLViewerRegion *regionp) LLSelectMgr::getInstance()->updateSelectionCenter(); - LLFloaterMove::sUpdateFlyingStatus(); +// LLFloaterMove::sUpdateFlyingStatus(); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + LLFloaterMove::sUpdateMovementStatus(); +// [/RLVa:KB] LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; mRegionChangedSignal(); @@ -1165,6 +1213,11 @@ LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const void LLAgent::sitDown() { +// [RLVa:KB] - Checked: RLVa-1.2.1 + if (!RlvActions::canGroundSit()) + return; +// [/RLVa:KB] + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); } @@ -1913,7 +1966,10 @@ std::ostream& operator<<(std::ostream &s, const LLAgent &agent) //----------------------------------------------------------------------------- BOOL LLAgent::needsRenderAvatar() { - if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) +// if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) +// [RLVa:KB] - Checked: RLVa-2.0.2 + if ( (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) || (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELF)) ) +// [/RLVa:KB] { return FALSE; } @@ -1924,7 +1980,10 @@ BOOL LLAgent::needsRenderAvatar() // TRUE if we need to render your own avatar's head. BOOL LLAgent::needsRenderHead() { - return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook()); +// [RLVa:KB] - Checked: RLVa-2.0.2 + return ((LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELFHEAD)); +// [/RLVa:KB] +// return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook()); } //----------------------------------------------------------------------------- @@ -2454,7 +2513,11 @@ void LLAgent::onAnimStop(const LLUUID& id) } else if (id == ANIM_AGENT_AWAY) { - clearAFK(); +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g + if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) + clearAFK(); +// [/RLVa:KB] +// clearAFK(); } else if (id == ANIM_AGENT_STANDUP) { @@ -3119,7 +3182,36 @@ void LLAgent::sendRevokePermissions(const LLUUID & target, U32 permissions) } } -void LLAgent::sendWalkRun(bool running) +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i +void LLAgent::setAlwaysRun() +{ + mbAlwaysRun = (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_ALWAYSRUN)); + sendWalkRun(); +} + +void LLAgent::setTempRun() +{ + mbTempRun = (!rlv_handler_t::isEnabled()) || (!gRlvHandler.hasBehaviour(RLV_BHVR_TEMPRUN)); + sendWalkRun(); +} + +void LLAgent::clearAlwaysRun() +{ + mbAlwaysRun = false; + sendWalkRun(); +} + +void LLAgent::clearTempRun() +{ + mbTempRun = false; + sendWalkRun(); +} +// [/RLVa:KB] + +//void LLAgent::sendWalkRun(bool running) +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i +void LLAgent::sendWalkRun() +// [/RLVa:KB] { LLMessageSystem* msgsys = gMessageSystem; if (msgsys) @@ -3128,7 +3220,10 @@ void LLAgent::sendWalkRun(bool running) msgsys->nextBlockFast(_PREHASH_AgentData); msgsys->addUUIDFast(_PREHASH_AgentID, getID()); msgsys->addUUIDFast(_PREHASH_SessionID, getSessionID()); - msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) ); +// msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) ); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(getRunning()) ); +// [/RLVa:KB] sendReliableMessage(); } } @@ -3970,10 +4065,13 @@ void LLAgent::onCapabilitiesReceivedAfterTeleport() } -void LLAgent::teleportRequest( - const U64& region_handle, - const LLVector3& pos_local, - bool look_at_from_camera) +//void LLAgent::teleportRequest( +// const U64& region_handle, +// const LLVector3& pos_local, +// bool look_at_from_camera) +// [RLVa:KB] - Checked: RLVa-2.0.0 +void LLAgent::teleportRequest(const U64& region_handle, const LLVector3& pos_local, const LLVector3& look_at) +// [/RLVa:KB] { LLViewerRegion* regionp = getRegion(); if (regionp && teleportCore(region_handle == regionp->getHandle())) @@ -3988,11 +4086,11 @@ void LLAgent::teleportRequest( msg->nextBlockFast(_PREHASH_Info); msg->addU64("RegionHandle", region_handle); msg->addVector3("Position", pos_local); - LLVector3 look_at(0,1,0); - if (look_at_from_camera) - { - look_at = LLViewerCamera::getInstance()->getAtAxis(); - } +// LLVector3 look_at(0,1,0); +// if (look_at_from_camera) +// { +// look_at = LLViewerCamera::getInstance()->getAtAxis(); +// } msg->addVector3("LookAt", look_at); sendReliableMessage(); } @@ -4001,6 +4099,18 @@ void LLAgent::teleportRequest( // Landmark ID = LLUUID::null means teleport home void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id) { +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // NOTE: we'll allow teleporting home unless both @tplm=n *and* @tploc=n restricted + if ( (rlv_handler_t::isEnabled()) && + ( ( (landmark_asset_id.notNull()) ? gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) + : gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC) ) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting())) )) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); + return; + } +// [/RLVa:KB] + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id)); startTeleportRequest(); } @@ -4093,6 +4203,22 @@ void LLAgent::restoreCanceledTeleportRequest() void LLAgent::teleportViaLocation(const LLVector3d& pos_global) { +// [RLVa:KB] - Checked: RLVa-2.0.0 + if ( (RlvActions::isRlvEnabled()) && (!RlvUtil::isForceTp()) ) + { + if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); + return; + } + + if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) + { + gRlvHandler.setCanCancelTp(false); + } + } +// [/RLVa:KB] + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocation(pos_global)); startTeleportRequest(); } @@ -4145,15 +4271,37 @@ void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global) } // Teleport to global position, but keep facing in the same direction -void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) +// [RLVa:KB] - Checked: RLVa-2.0.0 +void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at) { - mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global)); + if ( (RlvActions::isRlvEnabled()) && (!RlvUtil::isForceTp()) ) + { + if ( (RlvActions::isLocalTp(pos_global)) ? !RlvActions::canTeleportToLocal(pos_global) : !RlvActions::canTeleportToLocation() ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); + return; + } + + if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) + { + gRlvHandler.setCanCancelTp(false); + } + } + + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global, (look_at.isExactlyZero()) ? LLViewerCamera::getInstance()->getAtAxis() : look_at)); startTeleportRequest(); } +// [/RLVa:KB] +//void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) +//{ +// mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global)); +// startTeleportRequest(); +//} -void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global) +// [RLVa:KB] - Checked: RLVa-2.0.0 +void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at) { - mbTeleportKeepsLookAt = true; + mbTeleportKeepsLookAt = look_at.isExactlyZero(); if(!gAgentCamera.isfollowCamLocked()) { @@ -4162,8 +4310,23 @@ void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global) U64 region_handle = to_region_handle(pos_global); LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle)); - teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt()); + teleportRequest(region_handle, pos_local, look_at); } +// [/RLVa:KB] +//void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at) +//{ +// mbTeleportKeepsLookAt = true; +// +// if(!gAgentCamera.isfollowCamLocked()) +// { +// gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction +// } +// +// U64 region_handle = to_region_handle(pos_global); +// LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle)); +// teleportRequest(region_handle, pos_local, look_at); +// teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt()); +//} LLAgent::ETeleportState LLAgent::getTeleportState() const { @@ -4753,11 +4916,18 @@ void LLTeleportRequestViaLocation::restartTeleport() // LLTeleportRequestViaLocationLookAt //----------------------------------------------------------------------------- -LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal) - : LLTeleportRequestViaLocation(pPosGlobal) +// [RLVa:KB] - Checked: RLVa-2.0.0 +LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal, const LLVector3& look_at) + : LLTeleportRequestViaLocation(pPosGlobal), mLookAt(look_at) { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt created" << LL_ENDL; } +// [/RLVa:KB] + +//LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal) +// : LLTeleportRequestViaLocation(pPosGlobal) +//{ +//} LLTeleportRequestViaLocationLookAt::~LLTeleportRequestViaLocationLookAt() { @@ -4773,13 +4943,19 @@ bool LLTeleportRequestViaLocationLookAt::canRestartTeleport() void LLTeleportRequestViaLocationLookAt::startTeleport() { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::startTeleport" << LL_ENDL; - gAgent.doTeleportViaLocationLookAt(getPosGlobal()); +// [RLVa:KB] - Checked: RLVa-2.0.0 + gAgent.doTeleportViaLocationLookAt(getPosGlobal(), getLookAt()); +// [/RLVa:KB] +// gAgent.doTeleportViaLocationLookAt(getPosGlobal()); } void LLTeleportRequestViaLocationLookAt::restartTeleport() { LL_INFOS("Teleport") << "LLTeleportRequestViaLocationLookAt::restartTeleport" << LL_ENDL; - gAgent.doTeleportViaLocationLookAt(getPosGlobal()); +// [RLVa:KB] - Checked: RLVa-2.0.0 + gAgent.doTeleportViaLocationLookAt(getPosGlobal(), getLookAt()); +// [/RLVa:KB] +// gAgent.doTeleportViaLocationLookAt(getPosGlobal()); } // EOF diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 5ba1083d8efc345b2b7f48b138972da50758a7df..c20b56fe48a4ce3629a32250121e34ea61067cf9 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -410,19 +410,31 @@ class LLAgent : public LLOldEvents::LLObservable DOUBLETAP_SLIDERIGHT }; - void setAlwaysRun() { mbAlwaysRun = true; } - void clearAlwaysRun() { mbAlwaysRun = false; } - void setRunning() { mbRunning = true; } - void clearRunning() { mbRunning = false; } - void sendWalkRun(bool running); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + void setAlwaysRun(); + void setTempRun(); + void clearAlwaysRun(); + void clearTempRun(); + void sendWalkRun(); + bool getTempRun() { return mbTempRun; } + bool getRunning() const { return (mbAlwaysRun) || (mbTempRun); } +// [/RLVa:KB] +// void setAlwaysRun() { mbAlwaysRun = true; } +// void clearAlwaysRun() { mbAlwaysRun = false; } +// void setRunning() { mbRunning = true; } +// void clearRunning() { mbRunning = false; } +// void sendWalkRun(bool running); bool getAlwaysRun() const { return mbAlwaysRun; } - bool getRunning() const { return mbRunning; } +// bool getRunning() const { return mbRunning; } public: LLFrameTimer mDoubleTapRunTimer; EDoubleTapRunMode mDoubleTapRunMode; private: bool mbAlwaysRun; // Should the avatar run by default rather than walk? - bool mbRunning; // Is the avatar trying to run right now? +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + bool mbTempRun; +// [/RLVa:KB] +// bool mbRunning; // Is the avatar trying to run right now? bool mbTeleportKeepsLookAt; // Try to keep look-at after teleport is complete //-------------------------------------------------------------------- @@ -628,7 +640,10 @@ class LLAgent : public LLOldEvents::LLObservable void teleportHome() { teleportViaLandmark(LLUUID::null); } // Go home void teleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location void teleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated - void teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation +// [RLVa:KB] - Checked: RLVa-2.0.0 + void teleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at = LLVector3::zero);// To a global location, preserving camera rotation +// [/RLVa:KB] +// void teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation void teleportCancel(); // May or may not be allowed by server void restoreCanceledTeleportRequest(); bool canRestoreCanceledTeleport() { return mTeleportCanceled != NULL; } @@ -666,13 +681,19 @@ class LLAgent : public LLOldEvents::LLObservable bool hasPendingTeleportRequest(); void startTeleportRequest(); - void teleportRequest(const U64& region_handle, - const LLVector3& pos_local, // Go to a named location home - bool look_at_from_camera = false); +// [RLVa:KB] - Checked: RLVa-2.0.0 + void teleportRequest(const U64& region_handle, const LLVector3& pos_local, const LLVector3& look_at = LLVector3(0, 1, 0)); +// [/RLVa:KB] +// void teleportRequest(const U64& region_handle, +// const LLVector3& pos_local, // Go to a named location home +// bool look_at_from_camera = false); void doTeleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark void doTeleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location void doTeleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated - void doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation +// [RLVa:KB] - Checked: RLVa-2.0.0 + void doTeleportViaLocationLookAt(const LLVector3d& pos_global, const LLVector3& look_at);// To a global location, preserving camera rotation +// [/RLVa:KB] +// void doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation void handleTeleportFinished(); void handleTeleportFailed(); diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 8edb1a5f0b4d57eadb4a9afe5814045a715a5165..613e7eb78f52ad54759cc0c78cfa6b2bbf104898 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -50,6 +50,10 @@ #include "llvoavatarself.h" #include "llwindow.h" #include "llworld.h" +// [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -210,10 +214,18 @@ void LLAgentCamera::init() mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView"); mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView"); mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView"); +// [RLVa:KB] - Checked: RLVa-2.0.0 + mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW] = gSavedSettings.declareVec3("CameraOffsetRLVaView", LLVector3(mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW]->getDefault()), "Declared in code", LLControlVariable::PERSIST_NO); + mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->setHiddenFromSettingsEditor(true); +// [/RLVa:KB] mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView"); mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView"); mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView"); +// [RLVa:KB] - Checked: RLVa-2.0.0 + mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW] = gSavedSettings.declareVec3("FocusOffsetRLVaView", LLVector3(mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW]->getDefault()), "Declared in code", LLControlVariable::PERSIST_NO); + mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->setHiddenFromSettingsEditor(true); +// [/RLVa:KB] mCameraCollidePlane.clearVec(); mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"); @@ -802,7 +814,13 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) LLVector3d camera_offset_dir = mCameraFocusOffsetTarget; camera_offset_dir.normalize(); - mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); +// [RLVa:KB] - Checked: 2.0.0 + const LLVector3d focus_offset_target = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); + if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(focus_offset_target)) ) + return; + mCameraFocusOffsetTarget = focus_offset_target; +// [/RLVa:KB] +// mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); } startCameraAnimation(); } @@ -930,6 +948,11 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM ); } +// [RLVa:KB] - Checked: 2.0.0 + if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) ) + return; +// [/RLVa:KB] + mCameraFocusOffsetTarget = new_distance * camera_offset_unit; } @@ -990,6 +1013,11 @@ void LLAgentCamera::cameraOrbitIn(const F32 meters) new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM ); } +// [RLVa:KB] - Checked: 2.0.0 + if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) ) + return; +// [/RLVa:KB] + // Compute new camera offset mCameraFocusOffsetTarget = new_distance * camera_offset_unit; cameraZoomIn(1.f); @@ -1134,6 +1162,14 @@ void LLAgentCamera::updateCamera() mCameraUpVector = LLVector3::z_axis; //LLVector3 camera_skyward(0.f, 0.f, 1.f); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Set focus back on our avie if something changed it + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK)) && ((cameraThirdPerson()) || (cameraFollow())) && (!getFocusOnAvatar()) ) + { + setFocusOnAvatar(TRUE, FALSE); + } +// [/RLVa:KB] + U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode; validateFocusObject(); @@ -1913,6 +1949,44 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) // } } +// [RLVa:KB] - Checked: RLVa-2.0.0 + if ( (RlvActions::isRlvEnabled()) && ((CAMERA_MODE_THIRD_PERSON == mCameraMode) || (CAMERA_MODE_FOLLOW == mCameraMode)) && (RlvActions::isCameraDistanceClamped()) ) + { + m_fRlvMinDist = m_fRlvMaxDist = false; + + // Av-locked | Focus-locked | Result + // =================================================== + // T | T | skip focus => slam av + // T | F | skip focus => slam av + // F | T | skip av => slam focus + // F | F | clamp focus then av + bool fCamAvDistClamped, fCamAvDistLocked = false; float nCamAvDistLimitMin, nCamAvDistLimitMax; + if (fCamAvDistClamped = RlvActions::getCameraAvatarDistanceLimits(nCamAvDistLimitMin, nCamAvDistLimitMax)) + fCamAvDistLocked = nCamAvDistLimitMin == nCamAvDistLimitMax; + bool fCamOriginDistClamped, fCamOriginDistLocked = false; float nCamOriginDistLimitMin, nCamOriginDistLimitMax; + if (fCamOriginDistClamped = RlvActions::getCameraOriginDistanceLimits(nCamOriginDistLimitMin, nCamOriginDistLimitMax)) + fCamOriginDistLocked = nCamOriginDistLimitMin == nCamOriginDistLimitMax; + + // Check focus distance limits + if ( (fCamOriginDistClamped) && (!fCamAvDistLocked) ) + { + const LLVector3 offsetCameraLocal = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale"); + const LLVector3d offsetCamera(gAgent.getFrameAgent().rotateToAbsolute(offsetCameraLocal)); + const LLVector3d posFocusCam = frame_center_global + head_offset + offsetCamera; + if (clampCameraPosition(camera_position_global, posFocusCam, nCamOriginDistLimitMin, nCamOriginDistLimitMax)) + isConstrained = TRUE; + } + + // Check avatar distance limits + if ( (fCamAvDistClamped) && (fCamAvDistLocked || !fCamOriginDistClamped) ) + { + const LLVector3d posAvatarCam = gAgent.getPosGlobalFromAgent( (isAgentAvatarValid()) ? gAgentAvatarp->mHeadp->getWorldPosition() : gAgent.getPositionAgent() ); + if (clampCameraPosition(camera_position_global, posAvatarCam, nCamAvDistLimitMin, nCamAvDistLimitMax)) + isConstrained = TRUE; + } + } +// [/RLVa:KB] + // Don't let camera go underground F32 camera_min_off_ground = getCameraMinOffGround(); @@ -1933,6 +2007,49 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) return camera_position_global; } +// [RLVa:KB] - Checked: RLVa-2.0.0 +bool LLAgentCamera::allowFocusOffsetChange(const LLVector3d& offsetFocus) +{ + if (RlvActions::isCameraDistanceClamped()) + { + if ( ((CAMERA_MODE_THIRD_PERSON == getCameraMode()) || (CAMERA_MODE_FOLLOW == getCameraMode())) && ((m_fRlvMinDist) || (m_fRlvMaxDist)) ) + { + const LLVector3d posFocusGlobal = calcFocusPositionTargetGlobal(); + // Don't allow moving the focus offset if at minimum and moving closer (or if at maximum and moving further) to prevent camera warping + F32 nCurDist = llabs((posFocusGlobal + mCameraFocusOffsetTarget - m_posRlvRefGlobal).magVec()); + F32 nNewDist = llabs((posFocusGlobal + offsetFocus - m_posRlvRefGlobal).magVec()); + if ( ((m_fRlvMaxDist) && (nNewDist > nCurDist)) || ((m_fRlvMinDist) && (nNewDist < nCurDist)) ) + return false; + } + } + return true; +} + +bool LLAgentCamera::clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax) +{ + const LLVector3d offsetCamera = posCamGlobal - posCamRefGlobal; + + F32 nCamAvDist = llabs(offsetCamera.magVec()), nDistMult = NAN; + if (nCamAvDist > nDistMax) + { + nDistMult = nDistMax / nCamAvDist; + m_fRlvMaxDist = true; + } + else if (nCamAvDist < nDistMin) + { + nDistMult = nDistMin / nCamAvDist; + m_fRlvMinDist = true; + } + + if (!isnan(nDistMult)) + { + posCamGlobal = posCamRefGlobal + nDistMult * offsetCamera; + m_posRlvRefGlobal = posCamRefGlobal; + return true; + } + return false; +} +// [/RLVa:KB] LLVector3 LLAgentCamera::getCameraOffsetInitial() { @@ -2042,6 +2159,10 @@ void LLAgentCamera::resetCamera() void LLAgentCamera::changeCameraToMouselook(BOOL animate) { if (!gSavedSettings.getBOOL("EnableMouselook") +// [RLVa:KB] - Checked: RLVa-2.0.0 + || ( (RlvActions::isRlvEnabled()) && (!RlvActions::canChangeToMouselook()) ) +// [/RLVa:KB] + || LLViewerJoystick::getInstance()->getOverrideCamera()) { return; @@ -2067,8 +2188,8 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate) //gViewerWindow->stopGrab(); LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->hideCursor(); - gViewerWindow->moveCursorToCenter(); +// gViewerWindow->hideCursor(); +// gViewerWindow->moveCursorToCenter(); if (mCameraMode != CAMERA_MODE_MOUSELOOK) { @@ -2264,6 +2385,13 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() return; } +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) + { + return; + } +// [/RLVa:KB] + gAgent.standUp(); // force stand up gViewerWindow->getWindow()->resetBusyCount(); @@ -2325,6 +2453,26 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() void LLAgentCamera::switchCameraPreset(ECameraPreset preset) { +// [RLVa:KB] - Checked: RLVa-2.0.0 + if (RlvActions::isRlvEnabled()) + { + // Don't allow changing away from the our view if an object is restricting it + if (RlvActions::isCameraPresetLocked()) + preset = CAMERA_RLV_SETCAM_VIEW; + + // Don't reset anything if our view is already current + if ( (CAMERA_RLV_SETCAM_VIEW == preset) && (CAMERA_RLV_SETCAM_VIEW == mCameraPreset) ) + return; + + // Reset our view when switching away + if (CAMERA_RLV_SETCAM_VIEW != preset) + { + mCameraOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->resetToDefault(); + mFocusOffsetInitial[CAMERA_RLV_SETCAM_VIEW]->resetToDefault(); + } + } +// [/RLVa:KB] + //zoom is supposed to be reset for the front and group views mCameraZoomFraction = 1.f; diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index a4bc8434b0c982892ff99b8710e6a4d721ed9d4f..1967021452bed3b30b3cb5bd51e665853e22d7c9 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -56,7 +56,12 @@ enum ECameraPreset CAMERA_PRESET_FRONT_VIEW, /** "Above and to the left, over the shoulder, pulled back a little on the zoom" */ - CAMERA_PRESET_GROUP_VIEW + CAMERA_PRESET_GROUP_VIEW, + +// [RLVa:KB] - Checked: RLVa-2.0.0 + /* Used by RLVa */ + CAMERA_RLV_SETCAM_VIEW +// [/RLVa:KB] }; //------------------------------------------------------------------------ @@ -303,6 +308,18 @@ class LLAgentCamera F32 mHUDTargetZoom; // Target zoom level for HUD objects (used when editing) F32 mHUDCurZoom; // Current animated zoom level for HUD objects +// [RLVa:KB] - Checked: RLVa-2.0.0 + //-------------------------------------------------------------------- + // RLVa + //-------------------------------------------------------------------- +protected: + bool allowFocusOffsetChange(const LLVector3d& offsetFocus); + bool clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax); + + bool m_fRlvMaxDist; // True if the camera is at max distance + bool m_fRlvMinDist; // True if the camera is at min distance + LLVector3d m_posRlvRefGlobal; // Current reference point for distance calculations +// [/RLVa:KB] /******************************************************************************** ** ** diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 7887184a11b01ed3968a6c4f5298c1e7d0caf0bf..85bae5cd7592f6ecf22b81b039f588250fb28687 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -43,6 +43,11 @@ #include "lltoolgrab.h" #include "llhudeffectlookat.h" #include "llagentcamera.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "llvoavatarself.h" +// [/RLVa:KB] LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -179,8 +184,28 @@ void LLAgentListener::requestSit(LLSD const & event_data) const object = findObjectClosestTo(target_position); } +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.1.0j + // TODO-RLVa: [RLVa-1.2.1] Figure out how to call this? + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canSit(object)) ) + { + return; + } +// [/RLVa:KB] + if (object && object->getPCode() == LL_PCODE_VOLUME) { +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) ) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + return; + } + gRlvHandler.setSitSource(gAgent.getPositionGlobal()); + } +// [/RLVa:KB] + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID()); @@ -200,6 +225,14 @@ void LLAgentListener::requestSit(LLSD const & event_data) const void LLAgentListener::requestStand(LLSD const & event_data) const { +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + // TODO-RLVa: [RLVa-1.2.1] Figure out how to call this? + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) + { + return; + } +// [/RLVa:KB] + mAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 3410a37890505052f86db52601015e878f6f469c..8258e77caa2387699a1eb8d16ec3f72fa5830a19 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -38,6 +38,9 @@ #include "llviewerparcelmgr.h" #include "llvoavatarself.h" #include "llslurl.h" +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] //static void LLAgentUI::buildFullname(std::string& name) @@ -99,6 +102,18 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const // create a default name and description for the landmark std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName(); std::string region_name = region->getName(); +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d + // RELEASE-RLVa: [SL-2.0.0] Check ELocationFormat to make sure our switch still makes sense + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + parcel_name = RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL); + region_name = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + if (LOCATION_FORMAT_NO_MATURITY == fmt) + fmt = LOCATION_FORMAT_LANDMARK; + else if (LOCATION_FORMAT_FULL == fmt) + fmt = LOCATION_FORMAT_NO_COORDS; + } +// [/RLVa:KB] std::string sim_access_string = region->getSimAccessString(); std::string buffer; if( parcel_name.empty() ) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 013c40f557d8fd2a71e03102a917e44c6f4a414a..b117ff43c06741a0ee784115644f5f0e91b2be35 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -51,12 +51,22 @@ #include "llviewerwearable.h" #include "llwearablelist.h" #include "llfloaterperms.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include <boost/scoped_ptr.hpp> LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) +bool LLAgentWearables::mInitialWearablesLoaded = false; +// [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +bool LLAgentWearables::mInitialAttachmentsRequested = false; +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -666,6 +676,34 @@ const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 return LLUUID(); } +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) +void LLAgentWearables::getWearableItemIDs(uuid_vec_t& idItems) const +{ + for (wearableentry_map_t::const_iterator itWearableType = mWearableDatas.begin(); + itWearableType != mWearableDatas.end(); ++itWearableType) + { + getWearableItemIDs(itWearableType->first, idItems); + } +} + +void LLAgentWearables::getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const +{ + wearableentry_map_t::const_iterator itWearableType = mWearableDatas.find(eType); + if (mWearableDatas.end() != itWearableType) + { + for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin(); + itWearable != itWearableType->second.end(); ++itWearable) + { + const LLViewerWearable* pWearable = dynamic_cast<LLViewerWearable*>(*itWearable); + if (pWearable) + { + idItems.push_back(pWearable->getItemID()); + } + } + } +} +// [/RLVa:KB] + const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const { const LLViewerWearable *wearable = getViewerWearable(type,index); @@ -967,7 +1005,11 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo old_wearable->removeFromAvatar(); } } - clearWearableType(type); +// clearWearableType(type); +// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0) + // The line above shouldn't be needed + RLV_VERIFY(0 == getWearableCount(type)); +// [/RLVa:KB] } else { @@ -1134,6 +1176,13 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-2.2) + if (!mInitialWearablesLoaded) + { + mInitialWearablesLoaded = true; + mInitialWearablesLoadedSignal(); + } +// [/SL:KB] notifyLoadingFinished(); // Copy wearable params to avatar. @@ -1149,146 +1198,140 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // User has picked "wear on avatar" from a menu. -void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - //LLAgentDumper dumper("setWearableItem"); - if (isWearingItem(new_item->getUUID())) - { - LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; - return; - } - - const LLWearableType::EType type = new_wearable->getType(); - - if (!do_append) - { - // Remove old wearable, if any - // MULTI_WEARABLE: hardwired to 0 - LLViewerWearable* old_wearable = getViewerWearable(type,0); - if (old_wearable) - { - const LLUUID& old_item_id = old_wearable->getItemID(); - if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID())) - { - LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; - return; - } - - if (old_wearable->isDirty()) - { - // Bring up modal dialog: Save changes? Yes, No, Cancel - LLSD payload; - payload["item_id"] = new_item->getUUID(); - LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); - return; - } - } - } - - setWearableFinal(new_item, new_wearable, do_append); -} +//void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// //LLAgentDumper dumper("setWearableItem"); +// if (isWearingItem(new_item->getUUID())) +// { +// LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; +// return; +// } +// +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (!do_append) +// { +// // Remove old wearable, if any +// // MULTI_WEARABLE: hardwired to 0 +// LLViewerWearable* old_wearable = getViewerWearable(type,0); +// if (old_wearable) +// { +// const LLUUID& old_item_id = old_wearable->getItemID(); +// if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && +// (old_item_id == new_item->getUUID())) +// { +// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; +// return; +// } +// +// if (old_wearable->isDirty()) +// { +// // Bring up modal dialog: Save changes? Yes, No, Cancel +// LLSD payload; +// payload["item_id"] = new_item->getUUID(); +// LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); +// return; +// } +// } +// } +// +// setWearableFinal(new_item, new_wearable, do_append); +//} // static -bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - U32 index; - if (!gAgentWearables.getWearableIndex(wearable,index)) - { - LL_WARNS() << "Wearable not found" << LL_ENDL; - delete wearable; - return false; - } - if (!new_item) - { - delete wearable; - return false; - } - - switch(option) - { - case 0: // "Save" - gAgentWearables.saveWearable(wearable->getType(),index); - gAgentWearables.setWearableFinal(new_item, wearable); - break; - - case 1: // "Don't Save" - gAgentWearables.setWearableFinal(new_item, wearable); - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; - } - - delete wearable; - return false; -} +//bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) +//{ +// S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +// LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); +// U32 index; +// if (!gAgentWearables.getWearableIndex(wearable,index)) +// { +// LL_WARNS() << "Wearable not found" << LL_ENDL; +// delete wearable; +// return false; +// } +// switch(option) +// { +// case 0: // "Save" +// gAgentWearables.saveWearable(wearable->getType(),index); +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 1: // "Don't Save" +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 2: // "Cancel" +// break; +// +// default: +// llassert(0); +// break; +// } +// +// delete wearable; +// return false; +//} // Called from setWearableItem() and onSetWearableDialog() to actually set the wearable. // MULTI_WEARABLE: unify code after null objects are gone. -void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - const LLWearableType::EType type = new_wearable->getType(); - - if (do_append && getWearableItemID(type,0).notNull()) - { - new_wearable->setItemID(new_item->getUUID()); - const bool trigger_updated = false; - pushWearable(type, new_wearable, trigger_updated); - LL_INFOS() << "Added additional wearable for type " << type - << " size is now " << getWearableCount(type) << LL_ENDL; - checkWearableAgainstInventory(new_wearable); - } - else - { - // Replace the old wearable with a new one. - llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); - - LLViewerWearable *old_wearable = getViewerWearable(type,0); - LLUUID old_item_id; - if (old_wearable) - { - old_item_id = old_wearable->getItemID(); - } - new_wearable->setItemID(new_item->getUUID()); - setWearable(type,0,new_wearable); - - if (old_item_id.notNull()) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - gInventory.notifyObservers(); - } - LL_INFOS() << "Replaced current element 0 for type " << type - << " size is now " << getWearableCount(type) << LL_ENDL; - } -} +//void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (do_append && getWearableItemID(type,0).notNull()) +// { +// new_wearable->setItemID(new_item->getUUID()); +// const bool trigger_updated = false; +// pushWearable(type, new_wearable, trigger_updated); +// LL_INFOS() << "Added additional wearable for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// checkWearableAgainstInventory(new_wearable); +// } +// else +// { +// // Replace the old wearable with a new one. +// llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); +// +// LLViewerWearable *old_wearable = getViewerWearable(type,0); +// LLUUID old_item_id; +// if (old_wearable) +// { +// old_item_id = old_wearable->getItemID(); +// } +// new_wearable->setItemID(new_item->getUUID()); +// setWearable(type,0,new_wearable); +// +// if (old_item_id.notNull()) +// { +// gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); +// gInventory.notifyObservers(); +// } +// LL_INFOS() << "Replaced current element 0 for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// } +//} // User has picked "remove from avatar" from a menu. // static -void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) -{ - if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& - //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) - { - gAgentWearables.removeWearable(type,false,index); - } -} +//void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) +//{ +// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& +// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) +// { +// gAgentWearables.removeWearable(type,false,index); +// } +//} //static -void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) -{ - if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& - //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) - { - gAgentWearables.removeWearable(type,true,0); - } -} +//void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) +//{ +// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& +// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) +// { +// gAgentWearables.removeWearable(type,true,0); +// } +//} // Given a desired set of attachments, find what objects need to be // removed, and what additional inventory items need to be added. @@ -1402,6 +1445,34 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo { if (!isAgentAvatarValid()) return; +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0) + // RELEASE-RLVa: [SL-3.4] Check our callers and verify that erasing elements from the passed vector won't break random things + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + llvo_vec_t::iterator itObj = objects_to_remove.begin(); + while (objects_to_remove.end() != itObj) + { + const LLViewerObject* pAttachObj = *itObj; + if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + { + itObj = objects_to_remove.erase(itObj); + + // Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere) + bool fInCOF = LLAppearanceMgr::instance().isLinkedInCOF(pAttachObj->getAttachmentItemID()); + RLV_ASSERT(fInCOF); + if (!fInCOF) + { + LLAppearanceMgr::instance().registerAttachment(pAttachObj->getAttachmentItemID()); + } + } + else + { + ++itObj; + } + } + } +// [/RLVa:KB] + if (objects_to_remove.empty()) return; @@ -1443,6 +1514,10 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra const LLInventoryItem* item = *it; LLAttachmentsMgr::instance().addAttachmentRequest(item->getLinkedUUID(), 0, TRUE); } + +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + mInitialAttachmentsRequested = true; +// [/RLVa:KB] } // Returns false if the given wearable is already topmost/bottommost @@ -1641,6 +1716,13 @@ bool LLAgentWearables::changeInProgress() const return mCOFChangeInProgress; } +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) +boost::signals2::connection LLAgentWearables::addInitialWearablesLoadedCallback(const loaded_callback_t& cb) +{ + return mInitialWearablesLoadedSignal.connect(cb); +} +// [/SL:KB] + void LLAgentWearables::notifyLoadingStarted() { mCOFChangeInProgress = true; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 27102629104216d6e612d21cc484914c0b68fe83..730f738405d27c6b89ece2e40777a30e3c95667f 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -72,6 +72,12 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL areWearablesLoaded() const; +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) + bool areInitalWearablesLoaded() const { return mInitialWearablesLoaded; } +// [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + bool areInitialAttachmentsRequested() const { return mInitialAttachmentsRequested; } +// [/RLVa:KB] bool isCOFChangeInProgress() const { return mCOFChangeInProgress; } F32 getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); } void updateWearablesLoaded(); @@ -87,6 +93,10 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Accessors //-------------------------------------------------------------------- public: +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + void getWearableItemIDs(uuid_vec_t& idItems) const; + void getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const; +// [/RLVa:KB] const LLUUID getWearableItemID(LLWearableType::EType type, U32 index /*= 0*/) const; const LLUUID getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const; const LLViewerWearable* getWearableFromItemID(const LLUUID& item_id) const; @@ -103,15 +113,15 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable private: /*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed); public: - void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); +// void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); void setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables); void setWearableName(const LLUUID& item_id, const std::string& new_name); // *TODO: Move this into llappearance/LLWearableData ? void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index); protected: - void setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false); - static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable); +// void setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false); +// static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable); void addWearableToAgentInventory(LLPointer<LLInventoryCallback> cb, LLViewerWearable* wearable, @@ -143,8 +153,11 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Removing wearables //-------------------------------------------------------------------- public: - void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +// void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); private: +// [RLVa:KB] - Checked: 2010-05-11 (RLVa-1.2.0) + void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +// [/RLVa:KB] void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); @@ -174,8 +187,8 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Static UI hooks //-------------------------------------------------------------------- public: - static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); - static void userRemoveWearablesOfType(const LLWearableType::EType &type); +// static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); +// static void userRemoveWearablesOfType(const LLWearableType::EType &type); typedef std::vector<LLViewerObject*> llvo_vec_t; @@ -199,6 +212,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable typedef boost::function<void()> loaded_callback_t; typedef boost::signals2::signal<void()> loaded_signal_t; boost::signals2::connection addLoadedCallback(loaded_callback_t cb); +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) + boost::signals2::connection addInitialWearablesLoadedCallback(const loaded_callback_t& cb); +// [/SL:KB] bool changeInProgress() const; void notifyLoadingStarted(); @@ -207,12 +223,21 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable private: loading_started_signal_t mLoadingStartedSignal; // should be called before wearables are changed loaded_signal_t mLoadedSignal; // emitted when all agent wearables get loaded +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) + loaded_signal_t mInitialWearablesLoadedSignal; // emitted once when the initial wearables are loaded +// [/SL:KB] //-------------------------------------------------------------------- // Member variables //-------------------------------------------------------------------- private: static BOOL mInitialWearablesUpdateReceived; +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.2) + static bool mInitialWearablesLoaded; +// [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + static bool mInitialAttachmentsRequested; +// [/RLVa:KB] BOOL mWearablesLoaded; /** diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index ee49125711ab81e1483c32d8e15ab1bdce1df20a..d8588528c03a1816aaf2c50eb317da8779a07a1a 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -436,14 +436,39 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht if (callback && !callback.empty()) { - LLUUID id(LLUUID::null); - - if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) - { - id = result["category_id"]; - } +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + uuid_list_t ids; + switch (type) + { + case COPYLIBRARYCATEGORY: + if (result.has("category_id")) + { + ids.insert(result["category_id"]); + } + break; + case COPYINVENTORY: + { + AISUpdate::parseUUIDArray(result, "_created_items", ids); + AISUpdate::parseUUIDArray(result, "_created_categories", ids); + } + break; + default: + break; + } - callback(id); + // If we were feeling daring we'd call LLInventoryCallback::fire for every item but it would take additional work to investigate whether all LLInventoryCallback derived classes + // were designed to handle multiple fire calls (with legacy link creation only one would ever fire per link creation) so we'll be cautious and only call for the first one for now + // (note that the LL code as written below will always call fire once with the NULL UUID for anything but CopyLibraryCategoryCommand so even the above is an improvement) + callback( (!ids.empty()) ? *ids.begin() : LLUUID::null); +// [/SL:KB] +// LLUUID id(LLUUID::null); +// +// if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) +// { +// id = result["category_id"]; +// } +// +// callback(id); } } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index e97059014bd11fedf3847eb78041544de3d78cf9..200af0c67ff32d09cd695c90cef8e2d263432e2f 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -89,7 +89,10 @@ class AISUpdate void parseUpdate(const LLSD& update); void parseMeta(const LLSD& update); void parseContent(const LLSD& update); - void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + static void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +// [/SL:KB] +// void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); void parseLink(const LLSD& link_map); void parseItem(const LLSD& link_map); void parseCategory(const LLSD& link_map); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 3c3dda1765633a801b8425d9d6fd43ea051e67fb..f7272da333263b2caef4b07e2a414caa1c099216 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -60,6 +60,12 @@ #include "llappviewer.h" #include "llcoros.h" #include "lleventcoro.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include "llavatarpropertiesprocessor.h" @@ -634,16 +640,20 @@ class LLWearableHoldingPattern bool pollMissingWearables(); bool isMissingCompleted(); void recoverMissingWearable(LLWearableType::EType type); - void clearCOFLinksForMissingWearables(); +// void clearCOFLinksForMissingWearables(); void onWearableAssetFetch(LLViewerWearable *wearable); void onAllComplete(); +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) + bool pollStopped(); +// [/SL:KB] + typedef std::list<LLFoundData> found_list_t; found_list_t& getFoundList(); void eraseTypeToLink(LLWearableType::EType type); void eraseTypeToRecover(LLWearableType::EType type); - void setObjItems(const LLInventoryModel::item_array_t& items); +// void setObjItems(const LLInventoryModel::item_array_t& items); void setGestItems(const LLInventoryModel::item_array_t& items); bool isMostRecent(); void handleLateArrivals(); @@ -653,7 +663,7 @@ class LLWearableHoldingPattern private: found_list_t mFoundList; - LLInventoryModel::item_array_t mObjItems; +// LLInventoryModel::item_array_t mObjItems; LLInventoryModel::item_array_t mGestItems; typedef std::set<S32> type_set_t; type_set_t mTypesToRecover; @@ -730,10 +740,11 @@ void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type) mTypesToRecover.erase(type); } -void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) -{ - mObjItems = items; -} +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.1 +//void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) +//{ +// mObjItems = items; +//} void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items) { @@ -840,55 +851,55 @@ void LLWearableHoldingPattern::onAllComplete() if (isAgentAvatarValid()) { - LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; - LLAgentWearables::llvo_vec_t objects_to_remove; - LLAgentWearables::llvo_vec_t objects_to_retain; - LLInventoryModel::item_array_t items_to_add; - - LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, - objects_to_remove, - objects_to_retain, - items_to_add); - - LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() - << " attachments" << LL_ENDL; - - // Here we remove the attachment pos overrides for *all* - // attachments, even those that are not being removed. This is - // needed to get joint positions all slammed down to their - // pre-attachment states. - gAgentAvatarp->clearAttachmentOverrides(); - - if (objects_to_remove.size() || items_to_add.size()) - { - LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() - << " and add " << items_to_add.size() << " items" << LL_ENDL; - } - - // Take off the attachments that will no longer be in the outfit. - LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); - +// LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; +// LLAgentWearables::llvo_vec_t objects_to_remove; +// LLAgentWearables::llvo_vec_t objects_to_retain; +// LLInventoryModel::item_array_t items_to_add; +// +// LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, +// objects_to_remove, +// objects_to_retain, +// items_to_add); +// +// LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() +// << " attachments" << LL_ENDL; +// +// // Here we remove the attachment pos overrides for *all* +// // attachments, even those that are not being removed. This is +// // needed to get joint positions all slammed down to their +// // pre-attachment states. +// gAgentAvatarp->clearAttachmentOverrides(); +// +// if (objects_to_remove.size() || items_to_add.size()) +// { +// LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() +// << " and add " << items_to_add.size() << " items" << LL_ENDL; +// } +// +// // Take off the attachments that will no longer be in the outfit. +// LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); + // Update wearables. LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; LLAppearanceMgr::instance().updateAgentWearables(this); - // Restore attachment pos overrides for the attachments that - // are remaining in the outfit. - for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); - it != objects_to_retain.end(); - ++it) - { - LLViewerObject *objectp = *it; - if (!objectp->isAnimatedObject()) - { - gAgentAvatarp->addAttachmentOverridesForObject(objectp); - } - } - - // Add new attachments to match those requested. - LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; - LLAgentWearables::userAttachMultipleAttachments(items_to_add); +// // Restore attachment pos overrides for the attachments that +// // are remaining in the outfit. +// for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); +// it != objects_to_retain.end(); +// ++it) +// { +// LLViewerObject *objectp = *it; +// if (!objectp->isAnimatedObject()) +// { +// gAgentAvatarp->addAttachmentOverridesForObject(objectp); +// } +// } +// +// // Add new attachments to match those requested. +// LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; +// LLAgentWearables::userAttachMultipleAttachments(items_to_add); } if (isFetchCompleted() && isMissingCompleted()) @@ -926,6 +937,12 @@ bool LLWearableHoldingPattern::pollFetchCompletion() { // runway skip here? LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) + // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this)); + return true; +// [/SL:KB] } bool completed = isFetchCompleted(); @@ -996,6 +1013,11 @@ void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLView { // runway skip here? LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) + // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves + return; +// [/SL:KB] } LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; @@ -1047,19 +1069,32 @@ bool LLWearableHoldingPattern::isMissingCompleted() return mTypesToLink.size()==0 && mTypesToRecover.size()==0; } -void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() +//void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() +//{ +// for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) +// { +// LLFoundData &data = *it; +// if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) +// { +// // Wearable link that was never resolved; remove links to it from COF +// LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; +// LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); +// } +// } +//} + +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) +bool LLWearableHoldingPattern::pollStopped() { - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + // We have to keep on polling until we're sure that all callbacks have completed or they'll cause a crash + if ( (isFetchCompleted()) && (isMissingCompleted()) ) { - LLFoundData &data = *it; - if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) - { - // Wearable link that was never resolved; remove links to it from COF - LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); - } + delete this; + return true; } + return false; } +// [/SL:KB] bool LLWearableHoldingPattern::pollMissingWearables() { @@ -1067,6 +1102,12 @@ bool LLWearableHoldingPattern::pollMissingWearables() { // runway skip here? LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; + +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) + // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves + doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this)); + return true; +// [/SL:KB] } bool timed_out = isTimedOut(); @@ -1326,6 +1367,25 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) const std::string LLAppearanceMgr::sExpectedTextureName = "OutfitPreview"; +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2015-06-30 (Catznip-3.7) +static void removeDuplicateWearableItemsByAssetID(LLInventoryModel::item_array_t& items) +{ + std::set<LLUUID> idsAsset; + items.erase(std::remove_if(items.begin(), items.end(), + [&idsAsset](const LLViewerInventoryItem* pItem) + { + if (pItem->isWearableType()) + { + const LLUUID& idAsset = pItem->getAssetUUID(); + if ( (idAsset.notNull()) && (idsAsset.end() != idsAsset.find(idAsset)) ) + return true; + idsAsset.insert(idAsset); + } + return false; + }), items.end()); +} +// [/SL:KB] + const LLUUID LLAppearanceMgr::getCOF() const { return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); @@ -1483,6 +1543,13 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, continue; } +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item_to_wear, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + continue; + } +// [/RLVa:KB] + switch (item_to_wear->getType()) { case LLAssetType::AT_CLOTHING: @@ -1499,7 +1566,10 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, { LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1); - removeCOFItemLinks(item_id, cb); +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) + removeCOFItemLinks(item_id, NULL, true); +// [/SL:KB] +// removeCOFItemLinks(item_id, cb); } items_to_link.push_back(item_to_wear); @@ -1899,6 +1969,13 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { return false; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_REMOVE)) ) + { + return false; + } +// [/RLVa:KB] + LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); @@ -1918,6 +1995,13 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) return false; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_ADD)) ) + { + return false; + } +// [/RLVa:KB] + LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); @@ -1938,6 +2022,14 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) return false; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Block "Replace Current Outfit" if the user can't wear the new folder + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(outfit_cat_id, RLV_LOCK_ADD)) ) + { + return false; + } +// [/RLVa:KB] + // Check whether it's the base outfit. if (outfit_cat_id.isNull()) { @@ -2052,7 +2144,10 @@ void LLAppearanceMgr::filterWearableItems( S32 size = items_by_type[i].size(); if (size <= 0) continue; - S32 start_index = llmax(0,size-max_per_type); +// S32 start_index = llmax(0,size-max_per_type); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-05-11 (Catznip-2.0) + S32 start_index = llmax(0, size - ((LLWearableType::getAllowMultiwear((LLWearableType::EType)i)) ? max_per_type : 1)); +// [/SL:KB[ for (S32 j = start_index; j<size; j++) { items.push_back(items_by_type[i][j]); @@ -2061,6 +2156,8 @@ void LLAppearanceMgr::filterWearableItems( } } +//void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0) void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) { LLViewerInventoryCategory *pcat = gInventory.getCategory(category); @@ -2071,6 +2168,32 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) } LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; + LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new; + getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE); + updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category); +} + +void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, + LLInventoryModel::item_array_t& wear_items_new, + LLInventoryModel::item_array_t& obj_items_new, + LLInventoryModel::item_array_t& gest_items_new, + bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/, LLPointer<LLInventoryCallback> link_waiter /*= NULL*/) +// [/RLVa:KB] +{ +// LLViewerInventoryCategory *pcat = gInventory.getCategory(category); +// if (!pcat) +// { +// LL_WARNS() << "no category found for id " << category << LL_ENDL; +// return; +// } +// LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL; +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0) + LL_INFOS("Avatar") << "starting" << LL_ENDL; +// [/RLVa:KB] + const LLUUID cof = getCOF(); // Deactivate currently active gestures in the COF, if replacing outfit @@ -2090,39 +2213,87 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // Collect and filter descendents to determine new COF contents. - // - Body parts: always include COF contents as a fallback in case any - // required parts are missing. + // + // - Body parts: always include COF contents as a fallback in case any required parts are missing. + // // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); - getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); - if (append) - reverse(body_items.begin(), body_items.end()); +// getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Filter out any new body parts that can't be worn before adding them + if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) ) + body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR_REPLACE)), body_items_new.end()); + body_items.insert(body_items.end(), body_items_new.begin(), body_items_new.end()); +// [/RLVa:KB] + // NOTE-RLVa: we don't actually want to favour COF body parts over the folder's body parts (if only because it breaks force wear) +// if (append) +// reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. removeDuplicateItems(body_items); filterWearableItems(body_items, 1, 0); + // // - Wearables: include COF contents only if appending. + // LLInventoryModel::item_array_t wear_items; if (append) getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); - getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); +// [RLVa:KB] - Checked: RLVa-2.0.3 + else if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_REMOVE))) ) + { + // Make sure that all currently locked clothing layers remain in COF when replacing + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), RlvPredCanRemoveItem()), wear_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Filter out any new wearables that can't be worn before adding them + if ( (RlvActions::isRlvEnabled()) && ((gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) ) + wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), wear_items_new.end()); + wear_items.insert(wear_items.end(), wear_items_new.begin(), wear_items_new.end()); +// [/RLVa:KB] // Reduce wearables to max of one per type. removeDuplicateItems(wear_items); +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + removeDuplicateWearableItemsByAssetID(wear_items); +// [/SL:KB] filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); + // // - Attachments: include COF contents only if appending. + // LLInventoryModel::item_array_t obj_items; if (append) getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); - getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); +// [RLVa:KB] - Checked: RLVa-2.0.3 + else if ( (RlvActions::isRlvEnabled()) && ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_REMOVE))) ) + { + // Make sure that all currently locked attachments remain in COF when replacing + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), RlvPredCanRemoveItem()), obj_items.end()); + } +// [/RLVa:KB] +// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Filter out any new attachments that can't be worn before adding them + if ( (RlvActions::isRlvEnabled()) && ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ADD))) ) + obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), obj_items_new.end()); + obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end()); +// [/RLVa:KB] removeDuplicateItems(obj_items); + // // - Gestures: include COF contents only if appending. + // LLInventoryModel::item_array_t gest_items; if (append) getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); - getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); +// getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0) + gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end()); +// [/RLVa:KB] removeDuplicateItems(gest_items); // Create links to new COF contents. @@ -2138,7 +2309,11 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // Will link all the above items. // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). - LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); +// LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false); +// [RLVa:KB] Checked: 2015-05-05 (RLVa-1.4.12) + if (!link_waiter) + link_waiter = new LLUpdateAppearanceOnDestroy(false, false); +// [/RLVa:KB] LLSD contents = LLSD::emptyArray(); for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); @@ -2166,8 +2341,12 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) item_contents["type"] = LLAssetType::AT_LINK; contents.append(item_contents); } - const LLUUID& base_id = append ? getBaseOutfitUUID() : category; - LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +// const LLUUID& base_id = append ? getBaseOutfitUUID() : category; +// LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) + const LLUUID& base_id = (append) ? getBaseOutfitUUID() : idOutfit; + LLViewerInventoryCategory* base_cat = (base_id.notNull()) ? gInventory.getCategory(base_id) : NULL; +// [/RLVa:KB] if (base_cat && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) { LLSD base_contents; @@ -2219,6 +2398,14 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) LLInventoryItem::item_array_t items; std::vector< LLViewerWearable* > wearables; wearables.reserve(32); +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + uuid_vec_t idsCurrent; LLInventoryModel::item_array_t itemsNew; + if (rlv_handler_t::isEnabled()) + { + // Collect the item UUIDs of all currently worn wearables + gAgentWearables.getWearableItemIDs(idsCurrent); + } +// [/RLVa:KB] // For each wearable type, find the wearables of that type. for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) @@ -2233,13 +2420,60 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0) + // TODO-RLVa: [RLVa-1.2.1] This is fall-back code so if we don't ever trigger this code it can just be removed + // -> one way to trigger the assertion: + // 1) "Replace Outfit" on a folder with clothing and an attachment that goes @addoutfit=n + // 2) updateCOF will add/link the items into COF => no @addoutfit=n present yet => allowed + // 3) llOwnerSay("@addoutfit=n") executes + // 4) code below runs => @addoutfit=n conflicts with adding new wearables + // => if it's left as-is then the wearables won't get worn (but remain in COF which causes issues of its own) + // => if it's changed to debug-only then we make tge assumption that anything that makes it into COF is always OK +#ifdef RLV_DEBUG + // NOTE: make sure we don't accidentally block setting the initial wearables + if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType())) && + (!gAgentWearables.getWearableFromItemID(item->getUUID())) && (gAgentWearables.areWearablesLoaded()) ) + { + RLV_VERIFY(RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType())); + continue; + } +#endif // RLV_DEBUG +// [/RLVa:KB] items.push_back(item); wearables.push_back(wearable); +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) ) + { + // Remove the wearable from current item UUIDs if currently worn and requested, otherwise mark it as a new item + uuid_vec_t::iterator itItemID = std::find(idsCurrent.begin(), idsCurrent.end(), item->getUUID()); + if (idsCurrent.end() != itItemID) + idsCurrent.erase(itItemID); + else + itemsNew.push_back(item); + } +// [/RLVa:KB] } } } } +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) + if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) ) + { + // We need to report removals before additions or scripts will get confused + for (uuid_vec_t::const_iterator itItemID = idsCurrent.begin(); itItemID != idsCurrent.end(); ++itItemID) + { + const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(*itItemID); + if (pWearable) + RlvBehaviourNotifyHandler::onTakeOff(pWearable->getType(), true); + } + for (S32 idxItem = 0, cntItem = itemsNew.size(); idxItem < cntItem; idxItem++) + { + RlvBehaviourNotifyHandler::onWear(itemsNew.at(idxItem)->getWearableType(), true); + } + } +// [/RLVa:KB] + if(wearables.size() > 0) { gAgentWearables.setWearableOutfit(items, wearables); @@ -2377,14 +2611,18 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, { //checking integrity of the COF in terms of ordering of wearables, //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-03-01 (Catznip-3.7) + // Ordering information is pre-applied locally so no reason to reason to wait on the inventory backend + updateClothingOrderingInfo(LLUUID::null); +// [/SL:KB] - // As with enforce_item_restrictions handling above, we want - // to wait for the update callbacks, then (finally!) call - // updateAppearanceFromCOF() with no additional COF munging needed. - LLPointer<LLInventoryCallback> cb( - new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); - updateClothingOrderingInfo(LLUUID::null, cb); - return; +// // As with enforce_item_restrictions handling above, we want +// // to wait for the update callbacks, then (finally!) call +// // updateAppearanceFromCOF() with no additional COF munging needed. +// LLPointer<LLInventoryCallback> cb( +// new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); +// updateClothingOrderingInfo(LLUUID::null, cb); +// return; } if (!validateClothingOrderingInfo()) @@ -2417,6 +2655,17 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, remove_non_link_items(wear_items); remove_non_link_items(obj_items); remove_non_link_items(gest_items); +// [SL:KB] - Patch: Apperance-Misc | Checked: 2010-11-24 (Catznip-2.4) + // Since we're following folder links we might have picked up new duplicates, or exceeded MAX_CLOTHING_LAYERS + removeDuplicateItems(wear_items); + removeDuplicateItems(obj_items); + removeDuplicateItems(gest_items); + filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_LAYERS, LLAgentWearables::MAX_CLOTHING_LAYERS); +// [/SL:KB] +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + // Wearing two wearables that share the same asset causes some issues + removeDuplicateWearableItemsByAssetID(wear_items); +// [/SL:KB] dumpItemArray(wear_items,"asset_dump: wear_item"); dumpItemArray(obj_items,"asset_dump: obj_item"); @@ -2428,6 +2677,72 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, << " descendent_count " << cof->getDescendentCount() << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; } + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.2 + // Update attachments to match those requested. + if (isAgentAvatarValid()) + { + // Include attachments which should be in COF but don't have their link created yet + std::set<LLUUID> pendingAttachments; + if (LLAttachmentsMgr::instance().getPendingAttachments(pendingAttachments)) + { + for (const LLUUID& idAttachItem : pendingAttachments) + { + if ( (!gAgentAvatarp->isWearingAttachment(idAttachItem)) || (isLinkedInCOF(idAttachItem)) ) + { + LLAttachmentsMgr::instance().clearPendingAttachmentLink(idAttachItem); + continue; + } + + LLViewerInventoryItem* pAttachItem = gInventory.getItem(idAttachItem); + if (pAttachItem) + { + obj_items.push_back(pAttachItem); + } + } + } + + // (Start of LL code from LLWearableHoldingPattern::onAllComplete()) + LL_DEBUGS("Avatar") << self_av_string() << "Updating " << obj_items.size() << " attachments" << LL_ENDL; + + LLAgentWearables::llvo_vec_t objects_to_remove; + LLAgentWearables::llvo_vec_t objects_to_retain; + LLInventoryModel::item_array_t items_to_add; + LLAgentWearables::findAttachmentsAddRemoveInfo(obj_items, objects_to_remove, objects_to_retain, items_to_add); + + // Here we remove the attachment pos overrides for *all* + // attachments, even those that are not being removed. This is + // needed to get joint positions all slammed down to their + // pre-attachment states. + gAgentAvatarp->clearAttachmentOverrides(); + // (End of LL code) + + // Take off the attachments that will no longer be in the outfit. + // (but don't remove attachments until avatar is fully loaded - should reduce random attaching/detaching/reattaching at log-on) + if (gAgentAvatarp->isFullyLoaded()) + { + LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() << " attachments" << LL_ENDL; + LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); + } + + // (Start of LL code from LLWearableHoldingPattern::onAllComplete()) + // Restore attachment pos overrides for the attachments that are remaining in the outfit. + for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); it != objects_to_retain.end(); ++it) + { + LLViewerObject *objectp = *it; + if (!objectp->isAnimatedObject()) + { + gAgentAvatarp->addAttachmentOverridesForObject(objectp); + } + } + + // Add new attachments to match those requested. + LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; + LLAgentWearables::userAttachMultipleAttachments(items_to_add); + // (End of LL code) + } +// [/SL:KB] + if(!wear_items.size()) { LLNotificationsUtil::add("CouldNotPutOnOutfit"); @@ -2442,7 +2757,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, LLTimer hp_block_timer; LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; - holder->setObjItems(obj_items); +// holder->setObjItems(obj_items); holder->setGestItems(gest_items); // Note: can't do normal iteration, because if all the @@ -2459,6 +2774,9 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, // fetch failures (should be replaced by new defaults in // lost&found). U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); +// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2) + U32 missing_type = gSavedSettings.getU32("ForceMissingType"); +// [/RLVa:KB] if (item && item->getIsLinkType() && linked_item) { @@ -2469,10 +2787,25 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID ); - if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) +// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2) +#ifdef LL_RELEASE_FOR_DOWNLOAD + // Don't allow forcing an invalid wearable if the initial wearables aren't set yet, or if any wearable type is currently locked + if ( (!rlv_handler_t::isEnabled()) || + ((gAgentWearables.areInitalWearablesLoaded()) && (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE))) ) +#endif // LL_RELEASE_FOR_DOWNLOAD { - found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + if (missing_type != LLWearableType::WT_INVALID && missing_type == found.mWearableType) + { + continue; + } +// [/RLVa:KB] + if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } +// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2) } +// [/RLVa:KB] //pushing back, not front, to preserve order of wearables for LLAgentWearables holder->getFoundList().push_back(found); } @@ -2852,6 +3185,13 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, // MULTI-WEARABLES: make sure we don't go over clothing limits remove_inventory_item(inv_item->getUUID(), cb); } +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + else if ( (vitem->getWearableType() == wearable_type) && (vitem->getAssetUUID() == inv_item->getAssetUUID()) ) + { + // Only allow one wearable per unique asset + linked_already = true; + } +// [/SL:KB] } } @@ -2970,7 +3310,10 @@ class LLUpdateOnCOFLinkRemove : public LLInventoryCallback LLPointer<LLInventoryCallback> mCB; }; -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) +//void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, bool immediate_delete) +// [/SL:KB] { LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; gInventory.collectDescendents(LLAppearanceMgr::getCOF(), @@ -2979,10 +3322,20 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInve LLInventoryModel::EXCLUDE_TRASH); for (S32 i=0; i<item_array.size(); i++) { - const LLInventoryItem* item = item_array.at(i).get(); + const LLViewerInventoryItem* item = item_array.at(i).get(); if (item->getIsLinkType() && item->getLinkedUUID() == item_id) { - if (item->getType() == LLAssetType::AT_OBJECT) +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if (rlv_handler_t::isEnabled()) + { + RLV_ASSERT(rlvPredCanRemoveItem(item)); + } +// [/RLVa:KB] + +// if (item->getType() == LLAssetType::AT_OBJECT) +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if (immediate_delete) +// [/RLVa:KB] { // Immediate delete remove_inventory_item(item->getUUID(), cb, true); @@ -3013,6 +3366,12 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer const LLViewerInventoryItem* item = *it; if (item->getIsLinkType()) // we must operate on links only { +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) + if (rlv_handler_t::isEnabled()) + { + RLV_ASSERT(rlvPredCanRemoveItem(item)); + } +// [/RLVa:KB] remove_inventory_item(item->getUUID(), cb); } } @@ -3890,18 +4249,28 @@ void LLAppearanceMgr::wearBaseOutfit() updateCOF(base_outfit_id); } -void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) +//void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLPointer<LLInventoryCallback> cb /*= NULL*/, bool immediate_delete /*= false*/) +// [/SL:KB] { if (ids_to_remove.empty()) { LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; return; } - LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) +// LLPointer<LLInventoryCallback> cb = NULL; for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) { const LLUUID& id_to_remove = *it; const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); + + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(linked_item_id)) ) + { + continue; + } + LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); if (item && item->getType() == LLAssetType::AT_OBJECT) { @@ -3911,16 +4280,46 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) { continue; } - removeCOFItemLinks(linked_item_id, cb); + + if (!cb) + cb = new LLUpdateAppearanceOnDestroy(); + removeCOFItemLinks(linked_item_id, cb, immediate_delete); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + LLAttachmentsMgr::instance().clearPendingAttachmentLink(linked_item_id); +// [/SL:KB] addDoomedTempAttachment(linked_item_id); } -} - -void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) +// [/RLVa:KB] +//// LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +// if (!cb) +// { +// cb = new LLUpdateAppearanceOnDestroy; +// } +//// [/SL:KB] +// for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) +// { +// const LLUUID& id_to_remove = *it; +// const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); +//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +// removeCOFItemLinks(linked_item_id, cb, immediate_delete); +//// [/SL:KB] +//// removeCOFItemLinks(linked_item_id, cb); +// addDoomedTempAttachment(linked_item_id); +// } +} + +//void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove, LLPointer<LLInventoryCallback> cb /*= NULL*/, bool immediate_delete /*= false*/) +// [/SL:KB] { uuid_vec_t ids_to_remove; ids_to_remove.push_back(id_to_remove); - removeItemsFromAvatar(ids_to_remove); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) + removeItemsFromAvatar(ids_to_remove, cb, immediate_delete); +// [/SL:KB] +// removeItemsFromAvatar(ids_to_remove); } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index c274a8b04903e11cfdd7ec2a1801c5a66e4a43ce..b8b75538a388f01ac7254b87cb12edf348297609 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -55,6 +55,11 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> bool enforce_ordering = true, nullary_func_t post_update_func = no_op); void updateCOF(const LLUUID& category, bool append = false); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new, + LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new, + bool append = false, const LLUUID& idOutfit = LLUUID::null, LLPointer<LLInventoryCallback> link_waiter = NULL); +// [/RLVa:KB] void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append); @@ -147,6 +152,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> // Attachment link management void unregisterAttachment(const LLUUID& item_id); void registerAttachment(const LLUUID& item_id); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + bool getAttachmentInvLinkEnable() { return mAttachmentInvLinkEnabled; } +// [/SL:KB] void setAttachmentInvLinkEnable(bool val); // Add COF link to individual item. @@ -158,7 +166,10 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> bool isLinkedInCOF(const LLUUID& item_id); // Remove COF entries - void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL); +// void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL); +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) + void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL, bool immediate_delete = false); +// [/SL:KB] void removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb = NULL); void removeAllClothesFromAvatar(); void removeAllAttachmentsFromAvatar(); @@ -194,8 +205,15 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> bool updateBaseOutfit(); //Remove clothing or detach an object from the agent (a bodypart cannot be removed) - void removeItemsFromAvatar(const uuid_vec_t& item_ids); - void removeItemFromAvatar(const LLUUID& item_id); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) + void removeItemFromAvatar(const LLUUID& id_to_remove) { removeItemFromAvatar(id_to_remove, NULL, false); } + void removeItemFromAvatar(const LLUUID& id_to_remove, LLPointer<LLInventoryCallback> cb /*= NULL*/, bool immediate_delete /*= false*/); + + void removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) { removeItemsFromAvatar(ids_to_remove, NULL, false); } + void removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLPointer<LLInventoryCallback> cb /*= NULL*/, bool immediate_delete /*= false*/); +// [/SL:KB] +// void removeItemsFromAvatar(const uuid_vec_t& item_ids); +// void removeItemFromAvatar(const LLUUID& item_id); void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel); @@ -228,6 +246,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> static void onIdle(void *); void requestServerAppearanceUpdate(); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-06-27 (Catznip-3.7) + void syncCofVersionAndRefresh(); +// [/SL:KB] void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } std::string getAppearanceServiceURL() const; @@ -258,6 +279,7 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> static void onOutfitRename(const LLSD& notification, const LLSD& response); + bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b232a8c3bbfeb3bc6002aa8da53ef1f422c61065..5cc53f024bc701b05c9670b3f2d5d823597d9fa0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -95,6 +95,14 @@ #include "llprogressview.h" #include "llvocache.h" #include "llvopartgroup.h" +// [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4) +#include "llappearancemgr.h" +// [/SL:KB] +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] + #include "llweb.h" #include "llfloatertexturefetchdebugger.h" #include "llspellcheck.h" @@ -487,7 +495,11 @@ void idle_afk_check() { // check idle timers F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32(); - F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); +// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + // Enforce an idle time of 30 minutes if @allowidle=n restricted + F32 afk_timeout = (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) ? gSavedSettings.getS32("AFKTimeout") : 60 * 30; +// [/RLVa:KB] +// F32 afk_timeout = gSavedSettings.getS32("AFKTimeout"); if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK()) { LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL; @@ -2206,7 +2218,14 @@ void errorCallback(const std::string &error_string) // static info file. LLAppViewer::instance()->writeDebugInfo(); +// [SL:KB] - Patch: Viewer-Build | Checked: Catznip-2.4 +#if !LL_RELEASE_FOR_DOWNLOAD && LL_WINDOWS + DebugBreak(); +#else LLError::crashAndLoop(error_string); +#endif // LL_RELEASE_WITH_DEBUG_INFO && LL_WINDOWS +// [/SL:KB] +// LLError::crashAndLoop(error_string); } void LLAppViewer::initLoggingAndGetLastDuration() @@ -2866,6 +2885,21 @@ bool LLAppViewer::initConfiguration() LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", *ki)); } +// [RLVa:KB] - Patch: RLVa-2.1.0 + if (LLControlVariable* pControl = gSavedSettings.getControl(RLV_SETTING_MAIN)) + { + if ( (pControl->getValue().asBoolean()) && (pControl->hasUnsavedValue()) ) + { + pControl->resetToDefault(); + pControl->setValue(false); + + std::ostringstream msg; + msg << LLTrans::getString("RLVaToggleMessageLogin", LLSD().with("[STATE]", LLTrans::getString("RLVaToggleDisabled"))); + OSMessageBox(msg.str(), LLStringUtil::null, OSMB_OK); + } + } +// [/RLVa:KB] + return true; // Config was successful. } @@ -3111,16 +3145,28 @@ LLSD LLAppViewer::getViewerInfo() const LLViewerRegion* region = gAgent.getRegion(); if (region) { - LLVector3d pos = gAgent.getPositionGlobal(); - info["POSITION"] = ll_sd_from_vector3d(pos); - info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); - info["REGION"] = gAgent.getRegion()->getName(); - info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); - info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + if (RlvActions::canShowLocation()) + { +// [/RLVa:KB] + LLVector3d pos = gAgent.getPositionGlobal(); + info["POSITION"] = ll_sd_from_vector3d(pos); + info["POSITION_LOCAL"] = ll_sd_from_vector3(gAgent.getPosAgentFromGlobal(pos)); + info["REGION"] = gAgent.getRegion()->getName(); + info["HOSTNAME"] = gAgent.getRegion()->getHost().getHostName(); + info["HOSTIP"] = gAgent.getRegion()->getHost().getString(); +// info["SERVER_VERSION"] = gLastVersionChannel; + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + info["SLURL"] = slurl.getSLURLString(); +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + } + else + { + info["REGION"] = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } info["SERVER_VERSION"] = gLastVersionChannel; - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - info["SLURL"] = slurl.getSLURLString(); +// [/RLVa:KB] } // CPU @@ -3148,6 +3194,9 @@ LLSD LLAppViewer::getViewerInfo() const } #endif +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0) + info["RLV_VERSION"] = (rlv_handler_t::isEnabled()) ? RlvStrings::getVersionAbout() : "(disabled)"; +// [/RLVa:KB] info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); // Settings @@ -3304,7 +3353,10 @@ std::string LLAppViewer::getViewerInfoString(bool default_string) const } if (info.has("REGION")) { - support << "\n\n" << LLTrans::getString("AboutPosition", args, default_string); +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + support << "\n\n" << LLTrans::getString( (RlvActions::canShowLocation()) ? "AboutPosition" : "AboutPositionRLVShowLoc", args, default_string); +// [/RLVa:KB] +// support << "\n\n" << LLTrans::getString("AboutPosition", args); } support << "\n\n" << LLTrans::getString("AboutSystem", args, default_string); support << "\n"; @@ -5389,6 +5441,11 @@ void LLAppViewer::disconnectViewer() // close inventory interface, close all windows LLSidepanelInventory::cleanup(); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4) + // Destroying all objects below will trigger attachment detaching code and attempt to remove the COF links for them + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(false); +// [/SL:KB] + gAgentWearables.cleanup(); gAgentCamera.cleanup(); // Also writes cached agent settings to gSavedSettings diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index d3e66289d1a4f2b1efff1b5a01be693d53358ab3..0d51d581dbbb507b906e4acad94316ad46295116 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -35,16 +35,41 @@ #include "llviewerinventory.h" #include "llviewerregion.h" #include "message.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] const F32 COF_LINK_BATCH_TIME = 5.0F; const F32 MAX_ATTACHMENT_REQUEST_LIFETIME = 30.0F; const F32 MIN_RETRY_REQUEST_TIME = 5.0F; const F32 MAX_BAD_COF_TIME = 30.0F; +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 +class LLRegisterAttachmentCallback : public LLRequestServerAppearanceUpdateOnDestroy +{ +public: + LLRegisterAttachmentCallback() + : LLRequestServerAppearanceUpdateOnDestroy() + { + } + + ~LLRegisterAttachmentCallback() override + { + } + + void fire(const LLUUID& idItem) override + { + LLAttachmentsMgr::instance().onRegisterAttachmentComplete(idItem); + LLRequestServerAppearanceUpdateOnDestroy::fire(idItem); + } +}; +// [/SL:KB] + LLAttachmentsMgr::LLAttachmentsMgr(): mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME), - mDetachRequests("detach",MIN_RETRY_REQUEST_TIME), - mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME) + mDetachRequests("detach",MIN_RETRY_REQUEST_TIME) +// , mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME) { } @@ -52,9 +77,14 @@ LLAttachmentsMgr::~LLAttachmentsMgr() { } +//void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, +// const BOOL add) +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, const U8 attachment_pt, - const BOOL add) + const BOOL add, const BOOL fRlvForce /*=FALSE*/) +// [/RLVa:KB] { LLViewerInventoryItem *item = gInventory.getItem(item_id); @@ -72,6 +102,26 @@ void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, attachment.mItemID = item_id; attachment.mAttachmentPt = attachment_pt; attachment.mAdd = add; + +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) + if ( (RlvActions::isRlvEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && (gAgentWearables.areInitialAttachmentsRequested()) ) + { + const LLInventoryItem* pItem = gInventory.getItem(item_id); + if (!pItem) + return; + + LLViewerJointAttachment* pAttachPt = NULL; + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pItem, &pAttachPt); + if ( ((add) && ((RLV_WEAR_ADD & eWearMask) == 0)) || ((!add) && ((RLV_WEAR_REPLACE & eWearMask) == 0)) ) + return; + + if ( (0 == attachment_pt) && (NULL != pAttachPt) ) + attachment.mAttachmentPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt); + RlvAttachmentLockWatchdog::instance().onWearAttachment(pItem, (add) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE); + attachment.mAdd = true; + } +// [/RLVa:KB] + mPendingAttachments.push_back(attachment); mAttachmentRequests.addTime(item_id); @@ -79,6 +129,11 @@ void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id) { +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + if (item_id.isNull()) + return; +// [/SL:KB] + LLViewerInventoryItem *item = gInventory.getItem(item_id); LL_DEBUGS("Avatar") << "ATT attachment was requested " << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; @@ -112,7 +167,7 @@ void LLAttachmentsMgr::onIdle() expireOldDetachRequests(); - checkInvalidCOFLinks(); +// checkInvalidCOFLinks(); spamStatusInfo(); } @@ -221,6 +276,13 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments() { if (mRecentlyArrivedAttachments.size()) { + // [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + if (!LLAppearanceMgr::instance().getAttachmentInvLinkEnable()) + { + return; + } +// [/SL:KB] + // One or more attachments have arrived but have not yet been // processed for COF links if (mAttachmentRequests.empty()) @@ -259,17 +321,63 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments() } if (ids_to_link.size()) { - LLPointer<LLInventoryCallback> cb = new LLRequestServerAppearanceUpdateOnDestroy(); - for (uuid_vec_t::const_iterator uuid_it = ids_to_link.begin(); - uuid_it != ids_to_link.end(); ++uuid_it) - { - LLAppearanceMgr::instance().addCOFItemLink(*uuid_it, cb); - } +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + LLPointer<LLInventoryCallback> cb = new LLRegisterAttachmentCallback(); + for (const LLUUID& idAttach : ids_to_link) + { + if (std::find(mPendingAttachLinks.begin(), mPendingAttachLinks.end(), idAttach) == mPendingAttachLinks.end()) + { + LLAppearanceMgr::instance().addCOFItemLink(idAttach, cb); + mPendingAttachLinks.insert(idAttach); + } + } +// [/SL:KB] +// LLPointer<LLInventoryCallback> cb = new LLRequestServerAppearanceUpdateOnDestroy(); +// for (uuid_vec_t::const_iterator uuid_it = ids_to_link.begin(); +// uuid_it != ids_to_link.end(); ++uuid_it) +// { +// LLAppearanceMgr::instance().addCOFItemLink(*uuid_it, cb); +// } } mRecentlyArrivedAttachments.clear(); } } +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.2 +bool LLAttachmentsMgr::getPendingAttachments(std::set<LLUUID>& ids) const +{ + ids.clear(); + + // Returns the union of the LL maintained list of attachments that are waiting for link creation and our maintained list of attachments that are pending link creation + set_union(mRecentlyArrivedAttachments.begin(), mRecentlyArrivedAttachments.end(), mPendingAttachLinks.begin(), mPendingAttachLinks.end(), std::inserter(ids, ids.begin())); + + return !ids.empty(); +} + +void LLAttachmentsMgr::clearPendingAttachmentLink(const LLUUID& idItem) +{ + mPendingAttachLinks.erase(idItem); +} + +void LLAttachmentsMgr::onRegisterAttachmentComplete(const LLUUID& idAttachLink) +{ + const LLViewerInventoryItem* pAttachLink = gInventory.getItem(idAttachLink); + if (!pAttachLink) + return; + + const LLUUID& idAttachBase = pAttachLink->getLinkedUUID(); + + // Remove the attachment from the pending list + clearPendingAttachmentLink(idAttachBase); + + // It may have been detached already in which case we should remove the COF link + if ( (isAgentAvatarValid()) && (!gAgentAvatarp->isWearingAttachment(idAttachBase)) ) + { + LLAppearanceMgr::instance().removeCOFItemLinks(idAttachBase, NULL, true); + } +} +// [/SL:KB] + LLAttachmentsMgr::LLItemRequestTimes::LLItemRequestTimes(const std::string& op_name, F32 timeout): mOpName(op_name), mTimeout(timeout) @@ -398,6 +506,11 @@ void LLAttachmentsMgr::onDetachRequested(const LLUUID& inv_item_id) void LLAttachmentsMgr::onDetachCompleted(const LLUUID& inv_item_id) { +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.2 + // (mRecentlyArrivedAttachments doesn't need pruning since it'll check the attachment is actually worn before linking) + clearPendingAttachmentLink(inv_item_id); +// [/SL:KB] + LLTimer timer; LLInventoryItem *item = gInventory.getItem(inv_item_id); if (mDetachRequests.getTime(inv_item_id, timer)) @@ -416,18 +529,25 @@ void LLAttachmentsMgr::onDetachCompleted(const LLUUID& inv_item_id) << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; } - LL_DEBUGS("Avatar") << "ATT detached item flagging as questionable for COF link checking " - << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; - mQuestionableCOFLinks.addTime(inv_item_id); +// LL_DEBUGS("Avatar") << "ATT detached item flagging as questionable for COF link checking " +// << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; +// mQuestionableCOFLinks.addTime(inv_item_id); } bool LLAttachmentsMgr::isAttachmentStateComplete() const { - return mPendingAttachments.empty() - && mAttachmentRequests.empty() - && mDetachRequests.empty() - && mRecentlyArrivedAttachments.empty() - && mQuestionableCOFLinks.empty(); +// [SL:KB] - Patch: Appearance-Misc | Checked: Catznip-4.3 + return mPendingAttachments.empty() + && mAttachmentRequests.empty() + && mDetachRequests.empty() + && mRecentlyArrivedAttachments.empty() + && mPendingAttachLinks.empty(); +// [/SL:KB] +// return mPendingAttachments.empty() +// && mAttachmentRequests.empty() +// && mDetachRequests.empty() +// && mRecentlyArrivedAttachments.empty() +// && mQuestionableCOFLinks.empty(); } // Check for attachments that are (a) linked in COF and (b) not @@ -450,54 +570,54 @@ bool LLAttachmentsMgr::isAttachmentStateComplete() const // // See related: MAINT-5070, MAINT-4409 // -void LLAttachmentsMgr::checkInvalidCOFLinks() -{ - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), - cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; i<item_array.size(); i++) - { - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - const LLUUID& item_id = inv_item->getLinkedUUID(); - if (inv_item->getType() == LLAssetType::AT_OBJECT) - { - LLTimer timer; - bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); - bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); - if (is_wearing_attachment && is_flagged_questionable) - { - LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " - << (is_wearing_attachment ? "attached " : "") - <<"removing flag after " - << timer.getElapsedTimeF32() << " item " - << inv_item->getName() << " id " << item_id << LL_ENDL; - mQuestionableCOFLinks.removeTime(item_id); - } - } - } - - for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); - it != mQuestionableCOFLinks.end(); ) - { - LLItemRequestTimes::iterator curr_it = it; - ++it; - const LLUUID& item_id = curr_it->first; - LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); - if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) - { - if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) - { - LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " - << curr_it->second.getElapsedTimeF32() << " seconds for " - << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(item_id); - } - mQuestionableCOFLinks.erase(curr_it); - continue; - } - } -} +//void LLAttachmentsMgr::checkInvalidCOFLinks() +//{ +// LLInventoryModel::cat_array_t cat_array; +// LLInventoryModel::item_array_t item_array; +// gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +// cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); +// for (S32 i=0; i<item_array.size(); i++) +// { +// const LLViewerInventoryItem* inv_item = item_array.at(i).get(); +// const LLUUID& item_id = inv_item->getLinkedUUID(); +// if (inv_item->getType() == LLAssetType::AT_OBJECT) +// { +// LLTimer timer; +// bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); +// bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); +// if (is_wearing_attachment && is_flagged_questionable) +// { +// LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " +// << (is_wearing_attachment ? "attached " : "") +// <<"removing flag after " +// << timer.getElapsedTimeF32() << " item " +// << inv_item->getName() << " id " << item_id << LL_ENDL; +// mQuestionableCOFLinks.removeTime(item_id); +// } +// } +// } +// +// for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); +// it != mQuestionableCOFLinks.end(); ) +// { +// LLItemRequestTimes::iterator curr_it = it; +// ++it; +// const LLUUID& item_id = curr_it->first; +// LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); +// if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) +// { +// if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) +// { +// LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " +// << curr_it->second.getElapsedTimeF32() << " seconds for " +// << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; +// LLAppearanceMgr::instance().removeCOFItemLinks(item_id); +// } +// mQuestionableCOFLinks.erase(curr_it); +// continue; +// } +// } +//} void LLAttachmentsMgr::spamStatusInfo() { @@ -528,3 +648,28 @@ void LLAttachmentsMgr::spamStatusInfo() } #endif } + +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 +void LLAttachmentsMgr::refreshAttachments() +{ + if (!isAgentAvatarValid()) + return; + + for (const auto& kvpAttachPt : gAgentAvatarp->mAttachmentPoints) + { + for (const LLViewerObject* pAttachObj : kvpAttachPt.second->mAttachedObjects) + { + const LLUUID& idItem = pAttachObj->getAttachmentItemID(); + if ( (mAttachmentRequests.wasRequestedRecently(idItem)) || (pAttachObj->isTempAttachment()) ) + continue; + + AttachmentsInfo attachment; + attachment.mItemID = idItem; + attachment.mAttachmentPt = kvpAttachPt.first; + attachment.mAdd = true; + mPendingAttachments.push_back(attachment); + mAttachmentRequests.addTime(idItem); + } + } +} +// [/SL:KB] diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h index a4ef762e8b1b07a02efb185426c766b31739cfd1..d9ffdca7ba64734f6cab7e8ff22486a1f0653bf0 100644 --- a/indra/newview/llattachmentsmgr.h +++ b/indra/newview/llattachmentsmgr.h @@ -75,9 +75,14 @@ class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr> }; typedef std::deque<AttachmentsInfo> attachments_vec_t; +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) void addAttachmentRequest(const LLUUID& item_id, const U8 attachment_pt, - const BOOL add); + const BOOL add, const BOOL fRlvForce = FALSE); +// [/RLVa:KB] +// void addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, +// const BOOL add); void onAttachmentRequested(const LLUUID& item_id); void requestAttachments(attachments_vec_t& attachment_requests); static void onIdle(void *); @@ -89,6 +94,16 @@ class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr> bool isAttachmentStateComplete() const; +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.1 +public: + void clearPendingAttachmentLink(const LLUUID& idItem); + bool getPendingAttachments(std::set<LLUUID>& ids) const; + void refreshAttachments(); +protected: + void onRegisterAttachmentComplete(const LLUUID& idAttachLink); + friend class LLRegisterAttachmentCallback; +// [/SL:KB] + private: class LLItemRequestTimes: public std::map<LLUUID,LLTimer> @@ -111,7 +126,7 @@ class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr> void linkRecentlyArrivedAttachments(); void expireOldAttachmentRequests(); void expireOldDetachRequests(); - void checkInvalidCOFLinks(); +// void checkInvalidCOFLinks(); void spamStatusInfo(); // Attachments that we are planning to rez but haven't requested from the server yet. @@ -127,8 +142,13 @@ class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr> std::set<LLUUID> mRecentlyArrivedAttachments; LLTimer mCOFLinkBatchTimer; - // Attachments that are linked in the COF but may be invalid. - LLItemRequestTimes mQuestionableCOFLinks; +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.1 + // Attachments that have pending link creation + std::set<LLUUID> mPendingAttachLinks; +// [/SL:KB] + +// // Attachments that are linked in the COF but may be invalid. +// LLItemRequestTimes mQuestionableCOFLinks; }; #endif diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index f0b74e743957c012d71bde75dcf5a81199b8ee93..1f814afc79b1a393cf74cd48bf5d13d34bc5badd 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -74,6 +74,10 @@ #include "llsidepanelinventory.h" #include "llavatarname.h" #include "llagentui.h" +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] // Flags for kick message const U32 KICK_FLAGS_DEFAULT = 0x0; @@ -203,6 +207,15 @@ void LLAvatarActions::startIM(const LLUUID& id) if (id.isNull() || gAgent.getID() == id) return; +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); + return; + } +// [/RLVa:KB] + LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_im, _1, _2)); } @@ -238,6 +251,16 @@ void LLAvatarActions::startCall(const LLUUID& id) { return; } + +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); + return; + } +// [/RLVa:KB] + LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_cache_start_call, _1, _2)); } @@ -254,7 +277,17 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate id_array.reserve(ids.size()); for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { - id_array.push_back(*it); +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + const LLUUID& idAgent = *it; + if (!RlvActions::canStartIM(idAgent)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return; + } + id_array.push_back(idAgent); +// [/RLVa:KB] +// id_array.push_back(*it); } // create the new ad hoc voice session @@ -301,7 +334,17 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float id_array.reserve(ids.size()); for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { - id_array.push_back(*it); +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + const LLUUID& idAgent = *it; + if (!RlvActions::canStartIM(idAgent)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return; + } + id_array.push_back(idAgent); +// [/RLVa:KB] +// id_array.push_back(*it); } const std::string title = LLTrans::getString("conference-title"); LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, ids[0], id_array, false, floater_id); @@ -417,6 +460,17 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const { LLMessageSystem* msg = gMessageSystem; +// [RLVa:KB] - Checked: RLVa-2.0.0 + const LLUUID idRecipient = notification["substitutions"]["uuid"]; + std::string strMessage = response["message"]; + + // Filter the request message if the recipients is IM-blocked + if ( (RlvActions::isRlvEnabled()) && ((!RlvActions::canStartIM(idRecipient)) || (!RlvActions::canSendIM(idRecipient))) ) + { + strMessage = RlvStrings::getString(RLV_STRING_HIDDEN); + } +// [/RLVa:KB] + msg->newMessageFast(_PREHASH_ImprovedInstantMessage); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -434,7 +488,10 @@ void LLAvatarActions::teleport_request_callback(const LLSD& notification, const LLAgentUI::buildFullname(name); msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, response["message"]); +// [RLVa:KB] - Checked: RLVa-2.0.0 + msg->addStringFast(_PREHASH_Message, strMessage); +// [/RLVa:KB] +// msg->addStringFast(_PREHASH_Message, response["message"]); msg->addU32Fast(_PREHASH_ParentEstateID, 0); msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); @@ -453,14 +510,17 @@ void LLAvatarActions::teleportRequest(const LLUUID& id) { LLSD notification; notification["uuid"] = id; - LLAvatarName av_name; - if (!LLAvatarNameCache::get(id, &av_name)) - { - // unlikely ... they just picked this name from somewhere... - LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id)); - return; // reinvoke this when the name resolves - } - notification["NAME"] = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-1.5.0 + notification["NAME"] = LLSLURL("agent", id, (RlvActions::canShowName(RlvActions::SNC_TELEPORTREQUEST, id)) ? "completename" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] +// LLAvatarName av_name; +// if (!LLAvatarNameCache::get(id, &av_name)) +// { +// // unlikely ... they just picked this name from somewhere... +// LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::teleportRequest, id)); +// return; // reinvoke this when the name resolves +// } +// notification["NAME"] = av_name.getCompleteName(); LLSD payload; diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index c131dc641b4e78b45fa71c87f2c9dcc8f85779e8..3bcc61302fbf5596985128ecd6fb577550958e76 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -330,3 +330,13 @@ void LLAvatarIconCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarN } } } + +// [SL:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +BOOL LLAvatarIconCtrl::handleToolTip(S32 x, S32 y, MASK mask) +{ + // Don't show our tooltip if we were asked not to + if (!mDrawTooltip) + return FALSE; + return LLIconCtrl::handleToolTip(x, y, mask); +} +// [/SL:KB] diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h index a1dacd1a270a201a13038786c9c71c489f221604..7c0e570d899c853187ec710f00256b2591e0e82b 100644 --- a/indra/newview/llavatariconctrl.h +++ b/indra/newview/llavatariconctrl.h @@ -112,6 +112,10 @@ class LLAvatarIconCtrl public: virtual ~LLAvatarIconCtrl(); +// [SL:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask); +// [/SL:KB] + virtual void setValue(const LLSD& value); // LLAvatarPropertiesProcessor observer trigger diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index b0715a3afd38e54e22a6905e6371a6d684d00fee..676e8a5d80a1d0a5b11cf51771a9515484ce2444 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -141,6 +141,9 @@ LLAvatarList::LLAvatarList(const Params& p) , mShowSpeakingIndicator(p.show_speaking_indicator) , mShowPermissions(p.show_permissions_granted) , mShowCompleteName(false) +// [RLVa:KB] - Checked: RLVa-1.2.0 +, mRlvCheckShowNames(false) +// [/RLVa:KB] { setCommitOnSelectionChange(true); @@ -207,6 +210,10 @@ void LLAvatarList::draw() void LLAvatarList::clear() { getIDs().clear(); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // We need to be able to call this *somehow* and it actually makes moderate sense to call this in here + updateNoItemsMessage(mNameFilter); +// [/RLVa:KB] setDirty(true); LLFlatListViewEx::clear(); } @@ -442,6 +449,9 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is { LLAvatarListItem* item = new LLAvatarListItem(); item->setShowCompleteName(mShowCompleteName); +// [RLVa:KB] - Checked: RLVa-1.2.0 + item->setRlvCheckShowNames(mRlvCheckShowNames); +// [/RLVa:KB] // This sets the name as a side effect item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus); item->setOnline(mIgnoreOnlineStatus ? true : is_online); diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 1a672c279b1d94cec40d6f2fdc8a00dea0e5c372..0613434ebb4ae76db4509c4dc1a65bfca7d86088 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -92,6 +92,12 @@ class LLAvatarList : public LLFlatListViewEx // Return true if filter has at least one match. bool filterHasMatches(); +// [RLVa:KB] - Checked: RLVa-1.2.0 + void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; } + // We need this to be public since we call it from RlvUIEnabler::onToggleShowNames() + void updateAvatarNames(); +// [/RLVa:KB] + boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb); boost::signals2::connection setItemDoubleClickCallback(const mouse_signal_t::slot_type& cb); @@ -114,7 +120,7 @@ class LLAvatarList : public LLFlatListViewEx void updateLastInteractionTimes(); void rebuildNames(); void onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask); - void updateAvatarNames(); +// void updateAvatarNames(); private: @@ -130,6 +136,9 @@ class LLAvatarList : public LLFlatListViewEx bool mShowSpeakingIndicator; bool mShowPermissions; bool mShowCompleteName; +// [RLVa:KB] - RLVa-1.2.0 + bool mRlvCheckShowNames; +// [/RLVa:KB] LLTimer* mLITUpdateTimer; // last interaction time update timer std::string mIconParamName; diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index 396b69ae3a22bd10ba7a473934e3594eeb5a37a9..fde0734f61505d69738376a46bedc278a8b618f1 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -41,6 +41,10 @@ #include "llavatariconctrl.h" #include "lloutputmonitorctrl.h" #include "lltooldraganddrop.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] bool LLAvatarListItem::sStaticInitialized = false; S32 LLAvatarListItem::sLeftPadding = 0; @@ -76,6 +80,9 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/) mOnlineStatus(E_UNKNOWN), mShowInfoBtn(true), mShowProfileBtn(true), +// [RLVa:KB] - Checked: RLVa-1.2.0 + mRlvCheckShowNames(false), +// [/RLVa:KB] mShowPermissions(false), mShowCompleteName(false), mHovered(false), @@ -180,8 +187,13 @@ S32 LLAvatarListItem::notifyParent(const LLSD& info) void LLAvatarListItem::onMouseEnter(S32 x, S32 y, MASK mask) { getChildView("hovered_icon")->setVisible( true); - mInfoBtn->setVisible(mShowInfoBtn); - mProfileBtn->setVisible(mShowProfileBtn); +// mInfoBtn->setVisible(mShowInfoBtn); +// mProfileBtn->setVisible(mShowProfileBtn); +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool fRlvCanShowName = (!mRlvCheckShowNames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mAvatarId)); + mInfoBtn->setVisible( (mShowInfoBtn) && (fRlvCanShowName) ); + mProfileBtn->setVisible( (mShowProfileBtn) && (fRlvCanShowName) ); +// [/RLVa:KB] mHovered = true; LLPanel::onMouseEnter(x, y, mask); @@ -358,12 +370,18 @@ void LLAvatarListItem::onProfileBtnClick() BOOL LLAvatarListItem::handleDoubleClick(S32 x, S32 y, MASK mask) { - if(mInfoBtn->getRect().pointInRect(x, y)) +// if(mInfoBtn->getRect().pointInRect(x, y)) +// [RVLa:KB] - Checked: RLVa-1.2.2 + if ( (mInfoBtn->getVisible()) && (mInfoBtn->getEnabled()) && (mInfoBtn->getRect().pointInRect(x, y)) ) +// [/SL:KB] { onInfoBtnClick(); return TRUE; } - if(mProfileBtn->getRect().pointInRect(x, y)) +// if(mProfileBtn->getRect().pointInRect(x, y)) +// [RLVa:KB] - Checked: RLVa-1.2.2 + if ( (mProfileBtn->getVisible()) && (mProfileBtn->getEnabled()) && (mProfileBtn->getRect().pointInRect(x, y)) ) +// [/SL:KB] { onProfileBtnClick(); return TRUE; @@ -423,8 +441,16 @@ void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name) mGreyOutUsername = "[ " + av_name.getUserName(true) + " ]"; LLStringUtil::toLower(mGreyOutUsername); } - setAvatarName(name_string); - setAvatarToolTip(av_name.getUserName()); +// setAvatarName(name_string); +// setAvatarToolTip(av_name.getUserName()); +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool fRlvCanShowName = (!mRlvCheckShowNames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mAvatarId)); + + setAvatarName( (fRlvCanShowName) ? name_string : RlvStrings::getAnonym(av_name) ); + setAvatarToolTip( (fRlvCanShowName) ? av_name.getUserName() : RlvStrings::getAnonym(av_name) ); + // TODO-RLVa: bit of a hack putting this here. Maybe find a better way? + mAvatarIcon->setDrawTooltip(fRlvCanShowName); +// [/RLVa:KB] //requesting the list to resort notifyParent(LLSD().with("sort", LLSD())); diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index 36d18114aaec80f6d6a4484b9df94c5c8b41027e..96e4fc3cc7cc8f6b9e8e147160f73a858e02af0a 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -107,6 +107,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver void showLastInteractionTime(bool show); void setAvatarIconVisible(bool visible); void setShowCompleteName(bool show) { mShowCompleteName = show;}; +// [RLVa:KB] - Checked: RLVa-1.2.0 + void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; } +// [/RLVa:KB] const LLUUID& getAvatarId() const; std::string getAvatarName() const; @@ -212,6 +215,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver //Speaker indicator and avatar name coords are translated accordingly bool mShowInfoBtn; bool mShowProfileBtn; +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool mRlvCheckShowNames; +// [/RLVa:KB] /// indicates whether to show icons representing permissions granted bool mShowPermissions; diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 54c6c985d6b5d2c040601916e13d7de7558ec262..e19f1bd15c5944848448e07b67a25d1d647f701d 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -59,6 +59,10 @@ #include "llui.h" #include "llviewermenu.h" #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] // // Globals @@ -78,7 +82,10 @@ class LLChatBarGestureObserver : public LLGestureManagerObserver }; -extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +//extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2) +extern void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); +// [/RLVa:KB] // // Functions @@ -472,7 +479,11 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata ) S32 length = raw_text.length(); - if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences +// if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d + // RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional? + if ( (length > 0) && (raw_text[0] != '/') && (!RlvActions::hasBehaviour(RLV_BHVR_REDIRCHAT)) ) +// [/RLVa:KB] { gAgent.startTyping(); } @@ -584,6 +595,16 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1); } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b + // RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional? + if ( (0 == channel) && (RlvActions::isRlvEnabled()) ) + { + // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) + type = RlvActions::checkChatVolume(type); + animate &= !RlvActions::hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); + } +// [/RLVa:KB] + // Don't animate for chats people can't hear (chat to scripts) if (animate && (channel == 0)) { diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 1099d4bc09e1481233d1c41b3a64656ff5a5979f..3b4cdd022ae554036fb108e4e5092afe34509c71 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -65,6 +65,9 @@ #include "llurlaction.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) +#include "rlvcommon.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history"); @@ -96,6 +99,10 @@ class LLObjectIMHandler : public LLCommandHandler LLSD payload; payload["object_id"] = object_id; payload["owner_id"] = query_map["owner"]; +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + if (query_map.has("rlv_shownames")) + payload["rlv_shownames"] = query_map["rlv_shownames"]; +// [/RLVa:KB] payload["name"] = query_map["name"]; payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]); payload["group_owned"] = query_map["groupowned"]; @@ -111,6 +118,10 @@ class LLChatHistoryHeader: public LLPanel LLChatHistoryHeader() : LLPanel(), mInfoCtrl(NULL), +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + mShowContextMenu(true), + mShowInfoCtrl(true), +// [/RLVa:KB] mPopupMenuHandleAvatar(), mPopupMenuHandleObject(), mAvatarID(), @@ -594,7 +605,11 @@ class LLChatHistoryHeader: public LLPanel void showInspector() { - if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return; +// if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + // Don't double-click show the inspector if we're not showing the info control + if ( (!mShowInfoCtrl) || (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) ) return; +// [/RLVa:KB] if (mSourceType == CHAT_SOURCE_OBJECT) { @@ -663,8 +678,24 @@ class LLChatHistoryHeader: public LLPanel // Start with blank so sample data from XUI XML doesn't // flash on the screen - user_name->setValue( LLSD() ); - fetchAvatarName(); +// user_name->setValue( LLSD() ); +// fetchAvatarName(); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + if (!chat.mRlvNamesFiltered) + { + user_name->setValue( LLSD() ); + fetchAvatarName(); + } + else + { + // If the agent's chat was subject to @shownames=n we should display their anonimized name + mFrom = chat.mFromName; + user_name->setValue(mFrom); + user_name->setToolTip(mFrom); + setToolTip(mFrom); + updateMinUserNameWidth(); + } +// [/RLVa:KB] } else if (chat.mChatStyle == CHAT_STYLE_HISTORY || mSourceType == CHAT_SOURCE_AGENT) @@ -716,6 +747,15 @@ class LLChatHistoryHeader: public LLPanel if(mSourceType != CHAT_SOURCE_AGENT || mAvatarID.isNull()) icon->setDrawTooltip(false); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + // Don't show the context menu, info control or avatar icon tooltip if this chat was subject to @shownames=n + if ( (chat.mRlvNamesFiltered) && ((CHAT_SOURCE_AGENT == mSourceType) || (CHAT_SOURCE_OBJECT == mSourceType)) ) + { + mShowInfoCtrl = mShowContextMenu = false; + icon->setDrawTooltip(false); + } +// [/RLVa:KB] + switch (mSourceType) { case CHAT_SOURCE_AGENT: @@ -792,6 +832,10 @@ class LLChatHistoryHeader: public LLPanel void showContextMenu(S32 x,S32 y) { +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + if (!mShowContextMenu) + return; +// [/RLVa:KB] if(mSourceType == CHAT_SOURCE_SYSTEM) showSystemContextMenu(x,y); if(mAvatarID.notNull() && mSourceType == CHAT_SOURCE_AGENT) @@ -871,7 +915,10 @@ class LLChatHistoryHeader: public LLPanel void showInfoCtrl() { - const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +// const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + const bool isVisible = mShowInfoCtrl && !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +// [/RLVa:KB] if (isVisible) { const LLRect sticky_rect = mUserNameTextBox->getRect(); @@ -961,6 +1008,10 @@ class LLChatHistoryHeader: public LLPanel EChatSourceType mSourceType; std::string mFrom; LLUUID mSessionID; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Added: RLVa-1.2.0f + bool mShowContextMenu; + bool mShowInfoCtrl; +// [/RLVa:KB] S32 mMinUserNameWidth; const LLFontGL* mUserNameFont; @@ -1245,8 +1296,18 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull()) { - // for object IMs, create a secondlife:///app/objectim SLapp - std::string url = LLViewerChat::getSenderSLURL(chat, args); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + // NOTE-RLVa: we don't need to do any @shownames or @showloc filtering here because we'll already have an existing URL + std::string url = chat.mURL; + RLV_ASSERT( (url.empty()) || (std::string::npos != url.find("objectim")) ); + if ( (url.empty()) || (std::string::npos == url.find("objectim")) ) + { +// [/RLVa:KB] + // for object IMs, create a secondlife:///app/objectim SLapp + /*std::string*/ url = LLViewerChat::getSenderSLURL(chat, args); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + } +// [/RLVa:KB] // set the link for the object name to be the objectim SLapp // (don't let object names with hyperlinks override our objectim Url) @@ -1260,7 +1321,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL mEditor->appendText(chat.mFromName + delimiter, prependNewLineState, link_params); prependNewLineState = false; } - else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log) +// else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log) +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log && !chat.mRlvNamesFiltered) +// [/RLVa:KB] { LLStyle::Params link_params(body_message_params); link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID)); diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index 4f42868f1a19a61df788ad4ab0cbc28bb7159dd3..8896de14db5f6794002462b8578180044f3d821f 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -42,6 +42,10 @@ #include "llslurl.h" +// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f) +#include "rlvhandler.h" +// [/RLVa:KB] + static const S32 msg_left_offset = 10; static const S32 msg_right_offset = 10; static const S32 msg_height_pad = 5; @@ -183,7 +187,11 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) std::string fromName = notification["from"].asString(); // agent or object name mFromID = notification["from_id"].asUUID(); // agent id or object id mFromName = fromName; - + +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + mShowIconTooltip = notification.has("show_icon_tooltip") ? notification["show_icon_tooltip"].asBoolean() : true; +// [/RLVa:KB] + int sType = notification["source"].asInteger(); mSourceType = (EChatSourceType)sType; @@ -230,8 +238,15 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) style_params_name.font.name(font_name); style_params_name.font.size(font_style_size); - style_params_name.link_href = notification["sender_slurl"].asString(); - style_params_name.is_link = true; +// style_params_name.link_href = notification["sender_slurl"].asString(); +// style_params_name.is_link = true; +// [RLVa:KB] - Checked: 2011-12-13 (RLVa-1.4.6) | Added: RLVa-1.4.6 + if (notification.has("sender_slurl")) + { + style_params_name.link_href = notification["sender_slurl"].asString(); + style_params_name.is_link = true; + } +// [/RLVa:KB] mMsgText->appendText(str_sender, FALSE, style_params_name); @@ -394,7 +409,10 @@ void LLFloaterIMNearbyChatToastPanel::draw() LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false); if(icon) { - icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT); +// icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT); +// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + icon->setDrawTooltip( (mShowIconTooltip) && (mSourceType == CHAT_SOURCE_AGENT) ); +// [/RLVa:KB] if(mSourceType == CHAT_SOURCE_OBJECT) icon->setValue(LLSD("OBJECT_Icon")); else if(mSourceType == CHAT_SOURCE_SYSTEM) diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index f66670ec8c83a91c3ac61fce643b925261906abb..bf977002f335c25d26b3c4e423074aec996c2f09 100644 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -47,6 +47,9 @@ class LLFloaterIMNearbyChatToastPanel : public LLPanel LLFloaterIMNearbyChatToastPanel() : mIsDirty(false), +// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + mShowIconTooltip(true), +// [/RLVa:KB] mSourceType(CHAT_SOURCE_OBJECT) {}; public: @@ -91,6 +94,9 @@ class LLFloaterIMNearbyChatToastPanel : public LLPanel bool mIsDirty; +// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + bool mShowIconTooltip; +// [/RLVa:KB] }; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index dedb06c9459404a0b73fdfc3684949b86f62ff06..98e616f8f9b2c6ada01eb21d5e86209c773bfca5 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -36,6 +36,9 @@ #include "llsingleton.h" #include "llsyswellwindow.h" #include "llfloaternotificationstabbed.h" +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +#include "llchannelmanager.h" +// [/SL:KB] static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel"); static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notification"); @@ -237,6 +240,15 @@ bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNo { displayNotification = true; } +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + else if ("offer" == notification->getType()) + { + // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell + /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); + /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL; + displayNotification = (pToast) && (pToast->getCanBeStored()); + } +// [/SL:KB] else { displayNotification = false; diff --git a/indra/newview/lldaycyclemanager.cpp b/indra/newview/lldaycyclemanager.cpp index 803e2b2fb22e9544df263b883be8b6c326b1d5b3..b8d7b8ec3c1f4c5ea686332cd3d1c17bf3336676 100644 --- a/indra/newview/lldaycyclemanager.cpp +++ b/indra/newview/lldaycyclemanager.cpp @@ -30,6 +30,10 @@ #include "lldiriterator.h" +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +#include <boost/algorithm/string.hpp> +// [/RLVa:KB] + void LLDayCycleManager::getPresetNames(preset_name_list_t& names) const { names.clear(); @@ -60,6 +64,18 @@ void LLDayCycleManager::getPresetNames(preset_name_list_t& user, preset_name_lis } } +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +const std::string& LLDayCycleManager::findPreset(const std::string& strPresetName) +{ + for (dc_map_t::const_iterator itCycle = mDayCycleMap.begin(); itCycle != mDayCycleMap.end(); ++itCycle) + { + if (boost::iequals(itCycle->first, strPresetName)) + return itCycle->first; + } + return LLStringUtil::null; +} +// [/RLVa:KB] + void LLDayCycleManager::getUserPresetNames(preset_name_list_t& user) const { preset_name_list_t sys; // unused diff --git a/indra/newview/lldaycyclemanager.h b/indra/newview/lldaycyclemanager.h index 04db9d5dacedeaa6675f69fafbb19a590dc1ae02..73bbe05c4c1f4993c3d15d3b496dcf64f0dc733a 100644 --- a/indra/newview/lldaycyclemanager.h +++ b/indra/newview/lldaycyclemanager.h @@ -52,6 +52,9 @@ class LLDayCycleManager : public LLSingleton<LLDayCycleManager> void getPresetNames(preset_name_list_t& names) const; void getPresetNames(preset_name_list_t& user, preset_name_list_t& sys) const; void getUserPresetNames(preset_name_list_t& user) const; +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + const std::string& findPreset(const std::string& strPresetName); +// [/RLVa:KB] bool getPreset(const std::string name, LLWLDayCycle& day_cycle) const; bool getPreset(const std::string name, LLSD& day_cycle) const; diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 3eefcef7aac66263687d915f02da932539c5b579..20b24333aff1e5f459c135aa26ca6b5e20ef16f6 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -308,10 +308,16 @@ void LLDrawPoolTerrain::renderFullShader() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; - LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; - LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; - LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep; +// [/SL:KB] +// LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; +// LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; +// LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; +// LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -459,10 +465,16 @@ void LLDrawPoolTerrain::renderFull4TU() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; - LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; - LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; - LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep; +// [/SL:KB] +// LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; +// LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; +// LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; +// LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -661,10 +673,16 @@ void LLDrawPoolTerrain::renderFull2TU() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; - LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; - LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; - LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture *detail_texture0p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[0] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture1p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[1] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture2p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[2] : LLViewerFetchedTexture::sDefaultDiffuseImagep; + LLViewerTexture *detail_texture3p = (LLPipeline::sRenderTextures) ? compp->mDetailTextures[3] : LLViewerFetchedTexture::sDefaultDiffuseImagep; +// [/SL:KB] +// LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; +// LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; +// LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; +// LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index b1f40781f73e5bcdccd50ac111e41d928b8492cc..a653bbd89f9b501915283cfce0a824674fa01b0d 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -98,7 +98,11 @@ void LLDrawPoolTree::render(S32 pass) LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1); LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f); - gGL.getTexUnit(sDiffTex)->bind(mTexturep); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + LLViewerTexture* pTexture = (LLPipeline::sRenderTextures) ? mTexturep : LLViewerFetchedTexture::sDefaultDiffuseImagep; + gGL.getTexUnit(sDiffTex)->bind(pTexture); +// [/SL:KB] +// gGL.getTexUnit(sDiffTex)->bind(mTexturep); for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp index fa1c3b983ec2222f75a5025b0d63e16c4d151842..5c0492ea488a59229c195bc444ef17fddbba741a 100644 --- a/indra/newview/llenvmanager.cpp +++ b/indra/newview/llenvmanager.cpp @@ -35,6 +35,10 @@ #include "llwaterparammanager.h" #include "llwlhandlers.h" #include "llwlparammanager.h" +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +#include <boost/algorithm/string.hpp> +#include "rlvhandler.h" +// [/RLVa:KB] #include "lltrans.h" std::string LLWLParamKey::toString() const @@ -495,7 +499,10 @@ void LLEnvManagerNew::onRegionSettingsResponse(const LLSD& content) LLWLParamManager::instance().refreshRegionPresets(getRegionSettings().getSkyMap()); // If using server settings, update managers. - if (getUseRegionSettings()) +// if (getUseRegionSettings()) +// [RLVa:KB] - Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + if ( (getUseRegionSettings()) && (LLWLParamManager::getInstance()->mAnimator.getIsRunning()) ) +// [/RLVa:KB] { updateManagersFromPrefs(mInterpNextChangeMessage); } @@ -625,6 +632,14 @@ void LLEnvManagerNew::updateWaterFromPrefs(bool interpolate) void LLEnvManagerNew::updateManagersFromPrefs(bool interpolate) { LL_DEBUGS("Windlight")<<LL_ENDL; + +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + { + return; + } +// [/RLVa:KB] + // Apply water settings. updateWaterFromPrefs(interpolate); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 85ee33edb19234b99736aba2c106c52b4cd3a71e..170e7efa7612453722213854abd4ec76b0a27237 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -56,6 +56,9 @@ #include "llviewertexture.h" #include "llvoavatar.h" #include "llsculptidsize.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvhandler.h" +// [/RLVa:KB] #if LL_LINUX // Work-around spurious used before init warning on Vector4a @@ -169,6 +172,10 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mBoundingSphereRadius = 0.0f ; mHasMedia = FALSE ; + +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + mShowDiffTexture = true; +// [/SL:KB] } void LLFace::destroy() @@ -279,6 +286,15 @@ void LLFace::setTexture(U32 ch, LLViewerTexture* tex) return ; } +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + if ( (LLRender::DIFFUSE_MAP == ch) && (!mShowDiffTexture) ) + { + mOrigDiffTexture = tex; + if (LLViewerFetchedTexture::sDefaultDiffuseImagep.get() == mTexture[ch].get()) + return; + } +// [/SL:KB] + if(mTexture[ch].notNull()) { mTexture[ch]->removeFace(ch, this) ; @@ -2726,9 +2742,67 @@ LLViewerTexture* LLFace::getTexture(U32 ch) const { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + // Check whether the diffuse texture needs to be obscured or restored + if (mShowDiffTexture != LLPipeline::sRenderTextures) + setDefaultTexture(LLRender::DIFFUSE_MAP, !LLPipeline::sRenderTextures); +// [/SL:KB] + return mTexture[ch] ; } +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +bool LLFace::isDefaultTexture(U32 nChannel) const +{ + // NOTE: mShowDiffTexture gets flipped before the clear (good) but also before the restore (bad) and hence can't + // be used to tell whether we're usurping a texture channel for our own use + return (LLRender::DIFFUSE_MAP == nChannel) ? mOrigDiffTexture.notNull() : false; +} + +void LLFace::setDefaultTexture(U32 nChannel, bool fShowDefault) const +{ + bool fUpdated = false; + if ( (LLRender::DIFFUSE_MAP == nChannel) && (mVObjp) && (!mVObjp->isDead()) && ((LL_PCODE_VOLUME == mVObjp->getPCode()) || (LLViewerObject::LL_VO_PART_GROUP == mVObjp->getPCode())) ) + { + if ( ((mShowDiffTexture) && (fShowDefault)) || + ((!mShowDiffTexture) && (fShowDefault) && (mOrigDiffTexture.notNull()) && (mTexture[nChannel]) && (mTexture[nChannel]->getID() != LLViewerFetchedTexture::sDefaultDiffuseImagep->getID())) ) + { + if (mOrigDiffTexture.notNull()) + mShowDiffTexture = true; // Swap out the default texture + else + mOrigDiffTexture = mTexture[nChannel]; // Cache the original texture + + if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_TEXTURES)) || (!mVObjp->isAttachment()) ) + { + if (LL_PCODE_VOLUME == mVObjp->getPCode()) + const_cast<LLFace*>(this)->switchTexture(nChannel, LLViewerFetchedTexture::sDefaultDiffuseImagep); + else + const_cast<LLFace*>(this)->setTexture(nChannel, LLViewerFetchedTexture::sDefaultDiffuseImagep); + } + mShowDiffTexture = false; fUpdated = true; + } + else if ( (!mShowDiffTexture) && (!fShowDefault) && (mOrigDiffTexture.notNull()) ) + { + mShowDiffTexture = true; + if (LL_PCODE_VOLUME == mVObjp->getPCode()) + const_cast<LLFace*>(this)->switchTexture(nChannel, mOrigDiffTexture); + else + const_cast<LLFace*>(this)->setTexture(nChannel, mOrigDiffTexture); + mOrigDiffTexture = nullptr; fUpdated = true; + } + + if ((fUpdated) && (mDrawablep)) + { + gPipeline.markTextured(mDrawablep); + const_cast<LLDrawable*>(mDrawablep.get())->updateTexture(); + } + } + + // Always flip the flag even if we didn't obscure so we don't keep wasting cycles with negative checks + mShowDiffTexture = !fShowDefault; +} +// [/SL:KB] + void LLFace::setVertexBuffer(LLVertexBuffer* buffer) { if (buffer) diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 77861f7d2f9016b21e1f2e5e53b9236d6f5e836f..464fb0c5073d9fd8b5bb448174a882ff67947802 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -219,6 +219,11 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16> BOOL switchTexture() ; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + bool isDefaultTexture(U32 nChannel) const; + void setDefaultTexture(U32 nChannel, bool fShowDefault) const; +// [/SL:KB] + //vertex buffer tracking void setVertexBuffer(LLVertexBuffer* buffer); void clearVertexBuffer(); //sets mVertexBuffer to NULL @@ -293,7 +298,11 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16> F32 mBoundingSphereRadius ; bool mHasMedia ; - +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + mutable bool mShowDiffTexture; + mutable LLPointer<LLViewerTexture> mOrigDiffTexture; +// [/SL:KB] + protected: static BOOL sSafeRenderSelect; diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 33099db1b946c0b10f8ace73c6b1cd4e26eb95a3..f9f3f7921cd01a7ac0b1c349d22bea9386d82309 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -37,6 +37,10 @@ #include "llviewercontrol.h" #include "llviewerregion.h" // getCapability() #include "llworld.h" +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.2a) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] // Linden libraries #include "llavatarnamecache.h" // IDEVO @@ -281,6 +285,23 @@ void LLFloaterAvatarPicker::onRangeAdjust() void LLFloaterAvatarPicker::onList() { getChildView("ok_btn")->setEnabled(isSelectBtnEnabled()); + +// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.2a) | Modified: RLVa-1.2.0d + if (rlv_handler_t::isEnabled()) + { + LLTabContainer* pTabs = getChild<LLTabContainer>("ResidentChooserTabs"); + LLPanel* pNearMePanel = getChild<LLPanel>("NearMePanel"); + RLV_ASSERT( (pTabs) && (pNearMePanel) ); + if ( (pTabs) && (pNearMePanel) ) + { + // TODO-RLVa: check this for RlvActions::canShowName() + bool fRlvEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); + pTabs->enableTabButton(pTabs->getIndexForPanel(pNearMePanel), fRlvEnable); + if ( (!fRlvEnable) && (pTabs->getCurrentPanel() == pNearMePanel) ) + pTabs->selectTabByName("SearchPanel"); + } + } +// [/RLVa:KB] } void LLFloaterAvatarPicker::populateNearMe() @@ -608,7 +629,10 @@ BOOL LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask, std::string avatar_name = selection->getColumn(0)->getValue().asString(); if (dest_agent_id.notNull() && dest_agent_id != gAgentID) { - if (drop) +// if (drop) +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + if ( (drop) && (RlvActions::canStartIM(dest_agent_id)) ) +// [/RLVa:KB] { // Start up IM before give the item session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, dest_agent_id); diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 5a9cdbba44d6bfe3aee80e43f079528bf4e32147..fa1667de73d376c28ab9f968f674f232718f6660 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -104,7 +104,10 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) // Clean up the lists... floater->reset(); floater->mSaleInfo = sale_info; - floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); +// [RLVa:KB] - Checked: RLVa-2.0.0 + floater->mObjectSelection = LLSelectMgr::getInstance()->getSelection(); +// [/RLVa:KB] +// floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); LLSelectNode* node = selection->getFirstRootNode(); if (!node) diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index 4607b4ac411d5fb04ec7c4c92a29a9e8077d43a6..abc23ceb39733e34fc83d867380671fe4796dca0 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -103,7 +103,10 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) if (list) list->deleteAllItems(); - floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); +// [RLVa:KB] - Checked: RLVa-2.0.0 + floater->mObjectSelection = LLSelectMgr::getInstance()->getSelection(); +// [/RLVa:KB] +// floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); LLUUID owner_id; std::string owner_name; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index a6531ed7e1b9ae3acd7b1bb6597dd6d1bae59e79..269172f282afe882eff6da4f76ec0654c72a1b67 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -67,6 +67,11 @@ #include "llviewerchat.h" #include "lltranslate.h" #include "llautoreplace.h" +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; @@ -75,7 +80,10 @@ const S32 COLLAPSED_HEIGHT = 60; const S32 EXPANDED_MIN_HEIGHT = 150; // legacy callback glue -void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2) +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); +// [/RLVa:KB] struct LLChatTypeTrigger { std::string name; @@ -468,7 +476,10 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke() S32 length = raw_text.length(); - if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences +// if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d + if ( (length > 0) && (raw_text[0] != '/') && (!RlvActions::hasBehaviour(RLV_BHVR_REDIRCHAT)) ) +// [/RLVa:KB] { gAgent.startTyping(); } @@ -709,6 +720,15 @@ void LLFloaterIMNearbyChat::sendChatFromViewer(const LLWString &wtext, EChatType utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1); } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b + if ( (0 == channel) && (RlvActions::isRlvEnabled()) ) + { + // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) + type = RlvActions::checkChatVolume(type); + animate &= !RlvActions::hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); + } +// [/RLVa:KB] + // Don't animate for chats people can't hear (chat to scripts) if (animate && (channel == 0)) { @@ -854,8 +874,52 @@ LLWString LLFloaterIMNearbyChat::stripChannelNumber(const LLWString &mesg, S32* } } -void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel) +// [/RLVa:KB] { +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a + // Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc) + if ( (RlvActions::isRlvEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) ) + { + if (0 == channel) + { + // Clamp the volume of the chat if needed + type = RlvActions::checkChatVolume(type); + + // Redirect chat if needed + if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) && + (gRlvHandler.redirectChatOrEmote(utf8_out_text)) ) ) + { + return; + } + + // Filter public chat if sendchat restricted + if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) + gRlvHandler.filterChat(utf8_out_text, true); + } + else + { + // Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception) + if (!RlvActions::canSendChannel(channel)) + return; + + // Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers) + if (CHAT_CHANNEL_DEBUG == channel) + { + bool fIsEmote = RlvUtil::isEmote(utf8_out_text); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) || + ((!fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT))) || + ((fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE))) ) + { + return; + } + } + } + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; if (channel >= 0) diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 4cd91c53d85508cac022b6becdc6f551eb6f4ba6..9c06a28086ac65439ee5f9cffc52eda755c831ac 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -45,7 +45,13 @@ #include "llrootview.h" #include "lllayoutstack.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] + //add LLFloaterIMNearbyChatHandler to LLNotificationsUI namespace + using namespace LLNotificationsUI; static LLFloaterIMNearbyChatToastPanel* createToastPanel() @@ -493,6 +499,24 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, if(chat_msg.mText.empty()) return;//don't process empty messages +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if (RlvActions::isRlvEnabled()) + { + // NOTE-RLVa: we can only filter the *message* here since most everything else will already be part of "args" as well + LLChat& tmp_chat = const_cast<LLChat&>(chat_msg); + if ( (!RlvActions::canShowLocation()) && (!tmp_chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) ) + { + RlvUtil::filterLocation(tmp_chat.mText); + tmp_chat.mRlvLocFiltered = TRUE; + } + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) && (!tmp_chat.mRlvNamesFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) ) + { + RlvUtil::filterNames(tmp_chat.mText); + tmp_chat.mRlvNamesFiltered = TRUE; + } + } +// [/RLVa:KB] + LLFloaterReg::getInstance("im_container"); LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); @@ -506,7 +530,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, chat["chat_type"] = (S32)chat_msg.mChatType; chat["chat_style"] = (S32)chat_msg.mChatStyle; // Pass sender info so that it can be rendered properly (STORM-1021). - chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); +// chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); +// [RLVa:KB] - Checked: 2011-12-13 (RLVa-1.4.6) | Added: RLVa-1.4.6 + if ((CHAT_SOURCE_AGENT != chat_msg.mSourceType) || (!chat_msg.mRlvNamesFiltered)) + chat["sender_slurl"] = LLViewerChat::getSenderSLURL(chat_msg, args); +// [/RLVa:KB] if (chat_msg.mChatType == CHAT_TYPE_DIRECT && chat_msg.mText.length() > 0 && @@ -555,8 +583,11 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, LLFirstUse::otherAvatarChatFirst(); // Add sender to the recent people list. - LLRecentPeople::instance().add(chat_msg.mFromID); - +// [RLVa:KB] - Checked: RLVa-2.0.0 + if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, chat_msg.mFromID)) ) + LLRecentPeople::instance().add(chat_msg.mFromID); +// [/RLVa:KB] +// LLRecentPeople::instance().add(chat_msg.mFromID); } // Send event on to LLEventStream @@ -648,6 +679,10 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, LLUUID id; id.generate(); chat["id"] = id; +// [RLVa:KB] - Checked: RLVa-1.2.0 + if (RlvActions::isRlvEnabled()) + chat["show_icon_tooltip"] = !chat_msg.mRlvNamesFiltered; +// [/RLVa:KB] std::string r_color_name = "White"; F32 r_color_alpha = 1.0f; LLViewerChat::getChatColor( chat_msg, r_color_name, r_color_alpha); diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index a4ab1af9a80b040dff8118577fa02e1647d3b56a..b1319d9c10012fb8e40e6f0079f4c423bb2421b6 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -62,6 +62,10 @@ #include "llnotificationmanager.h" #include "llautoreplace.h" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] const F32 ME_TYPING_TIMEOUT = 4.0f; const F32 OTHER_TYPING_TIMEOUT = 9.0f; @@ -267,7 +271,60 @@ void LLFloaterIMSession::sendMsgFromInputEditor() void LLFloaterIMSession::sendMsg(const std::string& msg) { - const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); +// const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); + + if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) ) + { + const LLIMModel::LLIMSession* pIMSession = LLIMModel::instance().findIMSession(mSessionID); + RLV_ASSERT(pIMSession); + + bool fRlvFilter = !pIMSession; + if (pIMSession) + { + switch (pIMSession->mSessionType) + { + case LLIMModel::LLIMSession::P2P_SESSION: // One-on-one IM + fRlvFilter = !RlvActions::canSendIM(mOtherParticipantUUID); + break; + case LLIMModel::LLIMSession::GROUP_SESSION: // Group chat + fRlvFilter = !RlvActions::canSendIM(mSessionID); + break; + case LLIMModel::LLIMSession::ADHOC_SESSION: // Conference chat: allow if all participants can be sent an IM + { + if (!pIMSession->mSpeakers) + { + fRlvFilter = true; + break; + } + + LLSpeakerMgr::speaker_list_t speakers; + pIMSession->mSpeakers->getSpeakerList(&speakers, TRUE); + for (LLSpeakerMgr::speaker_list_t::const_iterator itSpeaker = speakers.begin(); + itSpeaker != speakers.end(); ++itSpeaker) + { + const LLSpeaker* pSpeaker = *itSpeaker; + if ( (gAgent.getID() != pSpeaker->mID) && (!RlvActions::canSendIM(pSpeaker->mID)) ) + { + fRlvFilter = true; + break; + } + } + } + break; + default: + fRlvFilter = true; + break; + } + } + + if (fRlvFilter) + { + utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM); + } + } +// [/RLVa:KB] if (mSessionInitialized) { diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 10088d20c2353e12f5c97361fac7f4cab68b032f..57a05b42fcfaada163a224376627b2c7d65393d2 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -42,6 +42,11 @@ #include "llviewercontrol.h" #include "llviewerobject.h" #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvui.h" +// [/RLVa:KB] //LLFloaterInspect* LLFloaterInspect::sInstance = NULL; @@ -101,11 +106,13 @@ void LLFloaterInspect::onOpen(const LLSD& key) mObjectSelection = LLSelectMgr::getInstance()->getSelection(); refresh(); } -void LLFloaterInspect::onClickCreatorProfile() + +// [RLVa:KB] - Checked: RLVa-2.0.1 +const LLSelectNode* LLFloaterInspect::getSelectedNode() /*const*/ { if(mObjectList->getAllSelected().size() == 0) { - return; + return NULL; } LLScrollListItem* first_selected =mObjectList->getFirstSelected(); @@ -120,32 +127,29 @@ void LLFloaterInspect::onClickCreatorProfile() return (obj_id == node->getObject()->getID()); } } func(first_selected->getUUID()); - LLSelectNode* node = mObjectSelection->getFirstNode(&func); - if(node) - { - LLAvatarActions::showProfile(node->mPermissions->getCreator()); - } + return mObjectSelection->getFirstNode(&func); } + return NULL; } -void LLFloaterInspect::onClickOwnerProfile() +void LLFloaterInspect::onClickCreatorProfile() { - if(mObjectList->getAllSelected().size() == 0) return; - LLScrollListItem* first_selected =mObjectList->getFirstSelected(); - - if (first_selected) - { - LLUUID selected_id = first_selected->getUUID(); - struct f : public LLSelectedNodeFunctor + const LLSelectNode* node = getSelectedNode(); + if(node) { - LLUUID obj_id; - f(const LLUUID& id) : obj_id(id) {} - virtual bool apply(LLSelectNode* node) + // Only anonymize the creator if they're also the owner or if they're a nearby avie + const LLUUID& idCreator = node->mPermissions->getCreator(); + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) && ((node->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator))) ) { - return (obj_id == node->getObject()->getID()); + return; } - } func(selected_id); - LLSelectNode* node = mObjectSelection->getFirstNode(&func); + LLAvatarActions::showProfile(idCreator); + } +} + +void LLFloaterInspect::onClickOwnerProfile() +{ + const LLSelectNode* node = getSelectedNode(); if(node) { if(node->mPermissions->isGroupOwned()) @@ -156,21 +160,108 @@ void LLFloaterInspect::onClickOwnerProfile() else { const LLUUID& owner_id = node->mPermissions->getOwner(); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id)) + return; LLAvatarActions::showProfile(owner_id); } } - } } void LLFloaterInspect::onSelectObject() { if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) { - getChildView("button owner")->setEnabled(true); - getChildView("button creator")->setEnabled(true); + if (!RlvActions::isRlvEnabled()) + { + getChildView("button owner")->setEnabled(true); + getChildView("button creator")->setEnabled(true); + } + else + { + const LLSelectNode* node = getSelectedNode(); + const LLUUID& idOwner = (node) ? node->mPermissions->getOwner() : LLUUID::null; + const LLUUID& idCreator = (node) ? node->mPermissions->getCreator() : LLUUID::null; + + // See LLFloaterInspect::onClickCreatorProfile() + getChildView("button owner")->setEnabled( (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idOwner)) || ((node) && (node->mPermissions->isGroupOwned())) ); + // See LLFloaterInspect::onClickOwnerProfile() + getChildView("button creator")->setEnabled( ((idOwner != idCreator) && (!RlvUtil::isNearbyAgent(idCreator))) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) ); + } } } +// [/RLVa:KB] + +//void LLFloaterInspect::onClickCreatorProfile() +//{ +// if(mObjectList->getAllSelected().size() == 0) +// { +// return; +// } +// LLScrollListItem* first_selected =mObjectList->getFirstSelected(); +// +// if (first_selected) +// { +// struct f : public LLSelectedNodeFunctor +// { +// LLUUID obj_id; +// f(const LLUUID& id) : obj_id(id) {} +// virtual bool apply(LLSelectNode* node) +// { +// return (obj_id == node->getObject()->getID()); +// } +// } func(first_selected->getUUID()); +// LLSelectNode* node = mObjectSelection->getFirstNode(&func); +// if(node) +// { +// LLAvatarActions::showProfile(node->mPermissions->getCreator()); +// } +// } +//} + +//void LLFloaterInspect::onClickOwnerProfile() +//{ +// if(mObjectList->getAllSelected().size() == 0) return; +// LLScrollListItem* first_selected =mObjectList->getFirstSelected(); +// +// if (first_selected) +// { +// LLUUID selected_id = first_selected->getUUID(); +// struct f : public LLSelectedNodeFunctor +// { +// LLUUID obj_id; +// f(const LLUUID& id) : obj_id(id) {} +// virtual bool apply(LLSelectNode* node) +// { +// return (obj_id == node->getObject()->getID()); +// } +// } func(selected_id); +// LLSelectNode* node = mObjectSelection->getFirstNode(&func); +// if(node) +// { +// if(node->mPermissions->isGroupOwned()) +// { +// const LLUUID& idGroup = node->mPermissions->getGroup(); +// LLGroupActions::show(idGroup); +// } +// else +// { +// const LLUUID& owner_id = node->mPermissions->getOwner(); +// LLAvatarActions::showProfile(owner_id); +// } +// +// } +// } +//} + +//void LLFloaterInspect::onSelectObject() +//{ +// if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) +// { +// getChildView("button owner")->setEnabled(true); +// getChildView("button creator")->setEnabled(true); +// } +//} LLUUID LLFloaterInspect::getSelectedUUID() { @@ -254,7 +345,11 @@ void LLFloaterInspect::refresh() // actual name and set a placeholder. if (LLAvatarNameCache::get(idOwner, &av_name)) { - owner_name = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idOwner)) || (obj->mPermissions->isGroupOwned()); + owner_name = (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] +// owner_name = av_name.getCompleteName(); } else { @@ -269,7 +364,12 @@ void LLFloaterInspect::refresh() if (LLAvatarNameCache::get(idCreator, &av_name)) { - creator_name = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + const LLUUID& idCreator = obj->mPermissions->getCreator(); + bool fRlvCanShowName = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) || ( (obj->mPermissions->getOwner() != idCreator) && (!RlvUtil::isNearbyAgent(idCreator)) ); + creator_name = (fRlvCanShowName) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] +// creator_name = av_name.getCompleteName(); } else { diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h index 44381eac96f27cf64919fcae7469ba5e9ebb2dd8..7f7f7377f05d02aa8b33429fae4e0f24e7674df8 100644 --- a/indra/newview/llfloaterinspect.h +++ b/indra/newview/llfloaterinspect.h @@ -36,6 +36,9 @@ class LLObjectSelection; class LLScrollListCtrl; class LLUICtrl; +// [RLVa:KB] - Checked: RLVa-2.0.1 +class LLSelectNode; +// [/RLVa:KB] class LLFloaterInspect : public LLFloater { @@ -61,6 +64,10 @@ class LLFloaterInspect : public LLFloater void setDirty() { mDirty = TRUE; } bool mDirty; +// [RLVa:KB] - Checked: RLVa-2.0.1 + const LLSelectNode* getSelectedNode() /*const*/; +// [/RLVa:KB] + private: void onGetOwnerNameCallback(); void onGetCreatorNameCallback(); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index bcb0dfe856fa5dca4a76faced1e3aba59be837fe..39baa52d902fa839eef406a1b04bed2c95722c87 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -108,6 +108,10 @@ #include "llteleporthistorystorage.h" #include "llproxy.h" #include "llweb.h" +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] #include "lllogininstance.h" // to check if logged in yet #include "llsdserialize.h" @@ -1328,6 +1332,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); +// [RLVa:KB] - Checked: 2013-05-11 (RLVa-1.4.9) + if (rlv_handler_t::isEnabled()) + { + getChild<LLUICtrl>("do_not_disturb_response")->setEnabled(!RlvActions::hasBehaviour(RLV_BHVR_SENDIM)); + } +// [/RLVa:KB] + // Reflections BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") && gGLManager.mHasCubeMap @@ -1371,8 +1382,14 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail"); // can be linked with control var LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText"); - ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); - +// ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a + // "Basic Shaders" can't be disabled - but can be enabled - under @setenv=n + bool fCtrlShaderEnable = LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"); + ctrl_shader_enable->setEnabled( + fCtrlShaderEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("VertexShaderEnable"))) ); +// [/RLVa:KB] + BOOL shaders = ctrl_shader_enable->get(); if (shaders) { @@ -1392,7 +1409,13 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() // *HACK just checks to see if we can use shaders... // maybe some cards that use shaders, but don't support windlight - ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders); +// ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders); +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a + // "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n + bool fCtrlWindLightEnable = fCtrlShaderEnable && shaders; + ctrl_wind_light->setEnabled( + fCtrlWindLightEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))) ); +// [/RLVa:KB] sky->setEnabled(ctrl_wind_light->get() && shaders); sky_text->setEnabled(ctrl_wind_light->get() && shaders); diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 64ad40f4195a7b73b353ded636c400b049fcf910..188cbc06d05d68fbc0d0ef01e693693e525122ac 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -60,6 +60,10 @@ #include "lluictrlfactory.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLPropertiesObserver @@ -280,7 +284,20 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("BtnCreator")->setEnabled(TRUE); getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(TRUE); - getChild<LLUICtrl>("LabelCreatorName")->setValue(av_name.getUserName()); +// [RLVa:KB] - Checked: RLVa-2.0.1 + // If the object creator matches the object owner we need to anonymize the creator field as well + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getCreatorUUID())) && + ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) ) + { + childSetEnabled("BtnCreator", FALSE); + getChild<LLUICtrl>("LabelCreatorName")->setValue(RlvStrings::getAnonym(av_name.getUserName())); + } + else + { + getChild<LLUICtrl>("LabelCreatorName")->setValue(av_name.getUserName()); + } +// [/RLVa:KB] +// getChild<LLUICtrl>("LabelCreatorName")->setValue(av_name.getUserName()); } else { @@ -295,6 +312,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) //////////////// if(perm.isOwned()) { +// [RLVa:KB] - Checked: RVLa-2.0.1 + bool fRlvCanShowOwner = true; +// [/RLVa:KB] std::string name; if (perm.isGroupOwned()) { @@ -305,8 +325,19 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) LLAvatarName av_name; LLAvatarNameCache::get(perm.getOwner(), &av_name); name = av_name.getUserName(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + if (RlvActions::isRlvEnabled()) + { + fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, perm.getOwner()); + if (!fRlvCanShowOwner) + name = RlvStrings::getAnonym(name); + } +// [/RLVa:KB] } - getChildView("BtnOwner")->setEnabled(TRUE); +// getChildView("BtnOwner")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner); +// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(TRUE); getChild<LLUICtrl>("LabelOwnerName")->setValue(name); @@ -539,6 +570,17 @@ void LLFloaterProperties::onClickCreator() if(!item) return; if(!item->getCreatorUUID().isNull()) { +// [RLVa:KB] - Checked: RLVa-1.2.1 + const LLUUID& idCreator = item->getCreatorUUID(); + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) ) + { + const LLPermissions& perm = item->getPermissions(); + if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == idCreator) ) || (RlvUtil::isNearbyAgent(idCreator)) ) + { + return; + } + } +// [/RLVa:KB] LLAvatarActions::showProfile(item->getCreatorUUID()); } } @@ -554,6 +596,10 @@ void LLFloaterProperties::onClickOwner() } else { +// [RLVa:KB] - Checked: RLVa-1.0.0 + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getPermissions().getOwner())) ) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 960fd9620d8a6bf66b9e3e1f8fa559b0d6c12be5..c602d2fbd1e1ae730288e72eb0d1c514319adce9 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -343,6 +343,14 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) if (regionp) { getChild<LLUICtrl>("sim_field")->setValue(regionp->getName()); +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +/* + if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) + { + childSetText("sim_field", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + } +*/ +// [/RLVa:KB] LLVector3d global_pos; global_pos.setVec(objectp->getPositionRegion()); setPosBox(global_pos); diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index fb202b4c406189156a8a0a86de2316aec649156e..3ded0430f55bf0f181e8fc35cca7803b755e55ec 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -30,6 +30,9 @@ #include "lluictrlfactory.h" //#include "llfirstuse.h" #include "llcombobox.h" +// [RLVa:KB] - Patch: RLVa-2.1.0 +#include "llsdserialize.h" +// [/RLVa:KB] #include "llspinctrl.h" #include "llcolorswatch.h" #include "llviewercontrol.h" @@ -209,6 +212,20 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) if (controlp) { +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a + // If "HideFromEditor" was toggled while the floater is open then we need to manually disable access to the control + // NOTE: this runs per-frame so there's no need to explictly handle onCommitSettings() or onClickDefault() + bool fEnable = !controlp->isHiddenFromSettingsEditor(); + spinner1->setEnabled(fEnable); + spinner2->setEnabled(fEnable); + spinner3->setEnabled(fEnable); + spinner4->setEnabled(fEnable); + color_swatch->setEnabled(fEnable); + childSetEnabled("val_text", fEnable); + childSetEnabled("boolean_combo", fEnable); + childSetEnabled("default_btn", fEnable); +// [/RLVa:KB] + eControlType type = controlp->type(); //hide combo box only for non booleans, otherwise this will result in the combo box closing every frame @@ -430,6 +447,15 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) color_swatch->setValue(sd); break; } +// [RLVa:KB] - Patch: RLVa-2.1.0 + case TYPE_LLSD: + { + std::ostringstream strLLSD; + LLSDSerialize::toPrettyNotation(sd, strLLSD); + mComment->setText(strLLSD.str()); + } + break; +// [/RLVa:KB] default: mComment->setText(std::string("unknown")); break; diff --git a/indra/newview/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp index 64ddeff1b0897251077ed15bbb1ef9c96a537f37..2828dec3c1f75d4a4b5f60ba6700ad2a8b6416e1 100644 --- a/indra/newview/llfloatersidepanelcontainer.cpp +++ b/indra/newview/llfloatersidepanelcontainer.cpp @@ -39,6 +39,10 @@ //static const std::string LLFloaterSidePanelContainer::sMainPanelName("main_panel"); +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +LLFloaterSidePanelContainer::validate_signal_t LLFloaterSidePanelContainer::mValidateSignal; +// [/RLVa:KB] + LLFloaterSidePanelContainer::LLFloaterSidePanelContainer(const LLSD& key, const Params& params) : LLFloater(key, params) { @@ -116,10 +120,25 @@ LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_na return panel; } +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +bool LLFloaterSidePanelContainer::canShowPanel(const std::string& floater_name, const LLSD& key) +{ + return mValidateSignal(floater_name, sMainPanelName, key); +} + +bool LLFloaterSidePanelContainer::canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key) +{ + return mValidateSignal(floater_name, panel_name, key); +} +// [/RLVa:KB] + void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const LLSD& key) { LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name); - if (floaterp) +// if (floaterp) +// [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8) + if ( (floaterp) && ((floaterp->getVisible()) || (LLFloaterReg::canShowInstance(floater_name, key))) && (canShowPanel(floater_name, key)) ) +// [/RLVa:KB] { floaterp->openChildPanel(sMainPanelName, key); } @@ -128,7 +147,10 @@ void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, con void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key) { LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name); - if (floaterp) +// if (floaterp) +// [RLVa:KB] - Checked: 2013-04-16 (RLVa-1.4.8) + if ( (floaterp) && ((floaterp->getVisible()) || (LLFloaterReg::canShowInstance(floater_name, key))) && (canShowPanel(floater_name, panel_name, key)) ) +// [/RLVa:KB] { floaterp->openChildPanel(panel_name, key); } diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h index 635514e26ca48292617703879a3da5275a786c62..5c37a10c38f8e3c397c3d2312990da3aae33ffab 100644 --- a/indra/newview/llfloatersidepanelcontainer.h +++ b/indra/newview/llfloatersidepanelcontainer.h @@ -57,6 +57,11 @@ class LLFloaterSidePanelContainer : public LLFloater LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params); +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + static bool canShowPanel(const std::string& floater_name, const LLSD& key); + static bool canShowPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key); +// [/RLVa:KB] + static void showPanel(const std::string& floater_name, const LLSD& key); static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key); @@ -80,6 +85,15 @@ class LLFloaterSidePanelContainer : public LLFloater } return panel; } + +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + // Used to determine whether a sidepanel can be shown +public: + typedef boost::signals2::signal<bool(const std::string&, const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t; + static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); } +private: + static validate_signal_t mValidateSignal; +// [/RLVa:KB] }; #endif // LL_LLFLOATERSIDEPANELCONTAINER_H diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 27197f0b065075055cef8c772c0a6f82247027a1..71851bb23a7bcf7d2935f4ef83a9f899667e7670 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -76,6 +76,10 @@ #include "llwindow.h" // copyTextToClipboard() #include <algorithm> +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) +#include "rlvhandler.h" +// [/RLVa:KB] + //--------------------------------------------------------------------------- // Constants //--------------------------------------------------------------------------- @@ -493,6 +497,10 @@ void LLFloaterWorldMap::draw() // getChildView("Clear")->setEnabled((BOOL)tracking_status); getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking()); getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) ); +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + childSetEnabled("Go Home", + (!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC))); +// [/RLVa:KB] setMouseOpaque(TRUE); getDragHandle()->setMouseOpaque(TRUE); @@ -667,7 +675,10 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) std::string tooltip(""); mTrackedStatus = LLTracker::TRACKING_LOCATION; LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking - LLTracker::trackLocation(pos_global, full_name, tooltip); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + LLTracker::trackLocation(pos_global, (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? full_name : RlvStrings::getString(RLV_STRING_HIDDEN).c_str(), tooltip); +// [/RLVa:KB] +// LLTracker::trackLocation(pos_global, full_name, tooltip); LLVector3d coord_pos = LLTracker::getTrackedPositionGlobal(); updateTeleportCoordsDisplay( coord_pos ); @@ -681,9 +692,25 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) // enable/disable teleport destination coordinates void LLFloaterWorldMap::enableTeleportCoordsDisplay( bool enabled ) { - childSetEnabled("teleport_coordinate_x", enabled ); - childSetEnabled("teleport_coordinate_y", enabled ); - childSetEnabled("teleport_coordinate_z", enabled ); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + LLUICtrl* pCtrl = getChild<LLUICtrl>("events_label"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + + pCtrl = getChild<LLUICtrl>("teleport_coordinate_x"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + pCtrl->setEnabled(enabled); + + pCtrl = getChild<LLUICtrl>("teleport_coordinate_y"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + pCtrl->setEnabled(enabled); + + pCtrl = getChild<LLUICtrl>("teleport_coordinate_z"); + pCtrl->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + pCtrl->setEnabled(enabled); +// [/RLVa:KB] +// childSetEnabled("teleport_coordinate_x", enabled ); +// childSetEnabled("teleport_coordinate_y", enabled ); +// childSetEnabled("teleport_coordinate_z", enabled ); } // update display of teleport destination coordinates - pos is in global coordinates @@ -722,7 +749,22 @@ void LLFloaterWorldMap::updateLocation() // Make sure we know where we are before setting the current user position std::string agent_sim_name; gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( agentPos, agent_sim_name ); - if ( gotSimName ) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + mSetToUserPosition = FALSE; + + // Fill out the location field + getChild<LLUICtrl>("location")->setValue(RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + + // update the coordinate display with location of avatar in region + updateTeleportCoordsDisplay( agentPos ); + + mSLURL = LLSLURL(); + } + else if (gotSimName) +// [/RLVa:KB] +// if ( gotSimName ) { mSetToUserPosition = FALSE; @@ -767,7 +809,16 @@ void LLFloaterWorldMap::updateLocation() updateTeleportCoordsDisplay( coord_pos ); // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL - if ( gotSimName ) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + mSLURL = LLSLURL(); + + childSetValue("location", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + } + else if (gotSimName) +// [/RLVa:KB] +// if ( gotSimName ) { mSLURL = LLSLURL(sim_name, pos_global); } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 950a6cfaef5b053b630bd70f9126baf8cfdcde4f..d22c40922add3d0e3c8d3a46a1fe0868e29485c3 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -56,6 +56,10 @@ #include "llappearancemgr.h" #include "llgesturelistener.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +// [/RLVa:KB] + // Longest time, in seconds, to wait for all animations to stop playing const F32 MAX_WAIT_ANIM_SECS = 30.f; @@ -527,6 +531,11 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) { if (!gesture) return; +// [RLVa:KB] - Checked: RLVa-2.0.0 | Handles: @sendgesture + if (!RlvActions::canPlayGestures()) + return; +// [/RLVa:KB] + // Reset gesture to first step gesture->mCurrentStep = 0; diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 3ab8fed2c6de93dab3a283993e9ac73afa603fc7..ca0054375a0e5eec43526622066fc930f02a749a 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -47,6 +47,12 @@ #include "llrecentpeople.h" #include "llviewerobjectlist.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: RLVa-1.2.2 +#include "llavatarnamecache.h" +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvui.h" +// [/RLVa:KB] // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a @@ -320,6 +326,19 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im { gIMMgr->addSystemMessage(im_session_id, message_name, args); } +// [RLVa:KB] - Checked: RLVa-1.2.0 + else if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) && (RlvUtil::isNearbyAgent(to_agent)) && (!RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + // Log to chat history if the user didn't drop on an IM session or a profile to avoid revealing the name of the recipient + std::string strMsgName = "inventory_item_offered-im"; LLSD args; LLAvatarName avName; + if (LLAvatarNameCache::get(to_agent, &avName)) + { + args["NAME"] = RlvStrings::getAnonym(avName); + strMsgName = "inventory_item_offered_rlv"; + } + gIMMgr->addSystemMessage(LLUUID::null, strMsgName, args); + } +// [/RLVa:KB] // If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat. else if (LLIMModel::getInstance()->findIMSession(session_id)) { @@ -430,7 +449,15 @@ void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent, logInventoryOffer(to_agent, im_session_id, item_name); // add buddy to recent people list - LLRecentPeople::instance().add(to_agent); +// LLRecentPeople::instance().add(to_agent); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile) + if ( (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || (RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + LLRecentPeople::instance().add(to_agent); + } +// [/RLVa:KB] } // static @@ -496,7 +523,15 @@ bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, << cat->getUUID() << LL_ENDL; // add buddy to recent people list - LLRecentPeople::instance().add(to_agent); +// LLRecentPeople::instance().add(to_agent); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile) + if ( (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, to_agent)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) || (RlvUIEnabler::hasOpenProfile(to_agent)) ) + { + LLRecentPeople::instance().add(to_agent); + } +// [/RLVa:KB] // Test out how many items are being given. LLViewerInventoryCategory::cat_array_t cats; diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index fea01786f35796454d72091d74678fe6b9646242..48b539d03c05d1f4b8af852c425d24d7327bec5c 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -63,6 +63,11 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llviewershadermgr.h" +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvmodifiers.h" +// [/RLVa:KB] #include <vector> @@ -72,6 +77,18 @@ const F32 PARCEL_POST_HEIGHT = 0.666f; // Returns true if you got at least one object void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) { +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + // Block rectangle selection if: + // - prevented from editing and no exceptions are set (see below for the case where exceptions are set) + // - prevented from interacting at all + if ( (rlv_handler_t::isEnabled()) && + ( ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!gRlvHandler.hasException(RLV_BHVR_EDIT))) || + (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) ) ) + { + return; + } +// [/RLVa:KB] + LLVector3 av_pos = gAgent.getPositionAgent(); F32 select_dist_squared = gSavedSettings.getF32("MaxSelectDistance"); select_dist_squared = select_dist_squared * select_dist_squared; @@ -136,6 +153,29 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) LLViewerCamera::getInstance()->setFar(new_far); LLViewerCamera::getInstance()->setNear(new_near); } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0g + if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) + { + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + + // We'll allow drag selection under fartouch, but only within the fartouch range + // (just copy/paste the code above us to make that work, thank you Lindens!) + LLVector3 relative_av_pos = av_pos; + relative_av_pos -= LLViewerCamera::getInstance()->getOrigin(); + + F32 new_far = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() + s_nFartouchDist; + F32 new_near = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() - s_nFartouchDist; + + new_near = llmax(new_near, 0.1f); + + LLViewerCamera::getInstance()->setFar(new_far); + LLViewerCamera::getInstance()->setNear(new_near); + + // Usurp these two + limit_select_distance = TRUE; + select_dist_squared = s_nFartouchDist * s_nFartouchDist; + } +// [/RLVa:KB] LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, center_x-width/2, center_y-height/2, width, height, limit_select_distance); @@ -210,6 +250,13 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) continue; } +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canEdit(vobjp)) ) + { + continue; + } +// [/RLVa:KB] + S32 result = LLViewerCamera::getInstance()->sphereInFrustum(drawable->getPositionAgent(), drawable->getRadius()); if (result) { diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 599790d2bb8e0d3591d488ddb0c6f8b71f21ec59..6b0a6d9dc4e7dbeecfe4fc1ec40ac543014ade4a 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -41,6 +41,12 @@ #include "llnotificationsutil.h" #include "llstatusbar.h" // can_afford_transaction() #include "groupchatlistener.h" +// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0) +#include "llslurl.h" +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] // // Globals @@ -205,6 +211,15 @@ void LLGroupActions::startCall(const LLUUID& group_id) return; } +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(group_id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString())); + return; + } +// [/RLVa:KB] + LLUUID session_id = gIMMgr->addSession(gdata.mName, IM_SESSION_GROUP_START, group_id, true); if (session_id == LLUUID::null) { @@ -278,7 +293,10 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response) // static void LLGroupActions::leave(const LLUUID& group_id) { - if (group_id.isNull()) +// if (group_id.isNull()) +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (!RlvActions::canChangeActiveGroup())) ) +// [/RLVa:KB] { return; } @@ -330,6 +348,13 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id) // static void LLGroupActions::activate(const LLUUID& group_id) { +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (!RlvActions::canChangeActiveGroup()) && (gRlvHandler.getAgentGroup() != group_id) ) + { + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ActivateGroup); msg->nextBlockFast(_PREHASH_AgentData); @@ -426,6 +451,15 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id) { if (group_id.isNull()) return LLUUID::null; +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if (!RlvActions::canStartIM(group_id)) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString())); + return LLUUID::null; + } +// [/RLVa:KB] + LLGroupData group_data; if (gAgent.getGroupData(group_id, group_data)) { diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 62414d3bbb745e3e2b607e59321f09abbd0f161c..6cd640dc90f049be8254324baad249d1356d2a2d 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -43,6 +43,9 @@ #include "llviewercontrol.h" // for gSavedSettings #include "llviewermenu.h" // for gMenuHolder #include "llvoiceclient.h" +// [RLVa:KB] - Checked: RLVa-2.0.3 +#include "rlvactions.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLGroupList> r("group_list"); S32 LLGroupListItem::sIconWidth = 0; @@ -281,8 +284,14 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) bool real_group_selected = selected_group_id.notNull(); // a "real" (not "none") group is selected // each group including "none" can be activated +// [RLVa:KB] - Checked: RLVa-1.3.0 if (userdata.asString() == "activate") - return gAgent.getGroupID() != selected_group_id; + return (gAgent.getGroupID() != selected_group_id) && (RlvActions::canChangeActiveGroup()); + else if (userdata.asString() == "leave") + return (real_group_selected) && ((gAgent.getGroupID() != selected_group_id) || (RlvActions::canChangeActiveGroup())); +// [/RLVa:KB] +// if (userdata.asString() == "activate") +// return gAgent.getGroupID() != selected_group_id; if (userdata.asString() == "call") return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 088d052533566f605d5e2b75d8fcf2af87a3b1a0..74cb92b5350559b9ecdc66c48e983c98543ebc2e 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1515,7 +1515,11 @@ void LLGroupMgr::notifyObservers(LLGroupChange gc) if(obs_it == mParticularObservers.end()) return; - observer_set_t& obs = obs_it->second; +// observer_set_t& obs = obs_it->second; +// [RLVa:KB] - Checked: RLVa-2.2 (General bugfix) + // Iterate over a *copy* of the observer list + observer_set_t obs = obs_it->second; +// [/RLVa:KB] for (observer_set_t::iterator ob_it = obs.begin(); ob_it != obs.end(); ++ob_it) { (*ob_it)->changed(group_id, gc); diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp index 6a2daeeb90882b1e683668d0749022beb111d44f..30e5519ac5144d90ecb43cbe1f443554c333dbec 100644 --- a/indra/newview/llhttpretrypolicy.cpp +++ b/indra/newview/llhttpretrypolicy.cpp @@ -64,6 +64,15 @@ void LLAdaptiveRetryPolicy::reset() init(); } +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-06-27 (Catznip-3.7) +// virtual +void LLAdaptiveRetryPolicy::cancelRetry() +{ + // This relies on the current implementation where mShouldRetry is set to true only on initialization + mShouldRetry = false; +} +// [/SL:KB] + bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header_time) { return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h index af07b4afecbfc5065b8a3f9fabdd5788f29f5d1a..d71e114c5ddc90edfff66ffb3befa6f5317f82ec 100644 --- a/indra/newview/llhttpretrypolicy.h +++ b/indra/newview/llhttpretrypolicy.h @@ -55,6 +55,9 @@ class LLHTTPRetryPolicy: public LLThreadSafeRefCount virtual bool shouldRetry(F32& seconds_to_wait) const = 0; virtual void reset() = 0; +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-06-27 (Catznip-3.7) + virtual void cancelRetry() = 0; +// [/SL:KB] }; // Very general policy with geometric back-off after failures, @@ -68,6 +71,9 @@ class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy void onSuccess(); void reset(); +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-06-27 (Catznip-3.7) + /*virtual*/ void cancelRetry(); +// [/SL:KB] // virtual void onFailure(S32 status, const LLSD& headers); diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index ef3b234f5066a16327b49b3380e5c19665b0861f..deca90ec09d6e7dac1c67ef658e26ba612468781 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -46,6 +46,10 @@ #include "llstatusbar.h" #include "llmenugl.h" #include "pipeline.h" +// [RLVa:KB] - Checked: RLVa-1.4.0 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] #include <boost/tokenizer.hpp> const F32 HORIZONTAL_PADDING = 15.f; @@ -242,7 +246,32 @@ void LLHUDText::renderText() void LLHUDText::setString(const std::string &text_utf8) { mTextSegments.clear(); - addLine(text_utf8, mColor); +// addLine(text_utf8, mColor); +// [RLVa:KB] - Checked: RLVa-2.0.3 + // NOTE: setString() is called for debug and map beacons as well + if (RlvActions::isRlvEnabled()) + { + std::string text(text_utf8); + if (RlvActions::canShowHoverText(mSourceObject)) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(text); + + bool fCanShowNearby = RlvActions::canShowNearbyAgents(); + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) || (!fCanShowNearby) ) + RlvUtil::filterNames(text, true, !fCanShowNearby); + } + else + { + text = ""; + } + addLine(text, mColor); + } + else + { + addLine(text_utf8, mColor); + } +// [/RLVa:KB] } void LLHUDText::clearString() @@ -644,3 +673,17 @@ F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font) return width; } } + +// [RLVa:KB] - Checked: RLVa-2.0.3 +void LLHUDText::refreshAllObjectText(EObjectTextFilter eObjFilter) +{ + for (LLHUDText* pText : sTextObjects) + { + if ((pText) && (!pText->mObjText.empty()) && (pText->mSourceObject) && (LL_PCODE_VOLUME == pText->mSourceObject->getPCode()) && + ((OTF_NONE == eObjFilter) || ((OTF_HUD_ATTACHMENTS == eObjFilter) && (pText->mSourceObject->isHUDAttachment())))) + { + pText->setString(pText->mObjText); + } + } +} +// [/RLVa:KB] diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index 36015d51f0452fd583757928c388991885403efc..0be9eb4f2e98e5df862285deac1e16b7a7de96af 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -124,6 +124,13 @@ class LLHUDText : public LLHUDObject static void reshape(); static void setDisplayText(BOOL flag) { sDisplayText = flag ; } +// [RLVa:KB] - Checked: RLVa-2.0.3 + const std::string& getObjectText() const { return mObjText; } + void setObjectText(const std::string &utf8string) { mObjText = utf8string; } + + enum EObjectTextFilter { OTF_NONE, OTF_HUD_ATTACHMENTS }; + static void refreshAllObjectText(EObjectTextFilter eObjFilter = OTF_NONE); +// [/RLVa:KB] protected: LLHUDText(const U8 type); @@ -161,6 +168,9 @@ class LLHUDText : public LLHUDObject ETextAlignment mTextAlignment; EVertAlignment mVertAlignment; BOOL mHidden; +// [RLVa:KB] - Checked: RLVa-1.0.0 + std::string mObjText; +// [/RLVa:KB] static BOOL sDisplayText ; static std::set<LLPointer<LLHUDText> > sTextObjects; diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index c3375a377967215d434c1d48d801f5215a2a524b..7c41468b779edef9f3fe8200f116d274f6dc0897 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -54,6 +54,12 @@ #include "llviewerwindow.h" #include "llviewerregion.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvui.h" +// [/RLVa:KB] #include <boost/regex.hpp> #include "boost/lexical_cast.hpp" @@ -257,6 +263,9 @@ void inventory_offer_handler(LLOfferInfo* info) } else { +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + args["NAME_LABEL"] = LLSLURL("agent", info->mFromID, "completename").getSLURLString(); +// [/SL:KB] args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString(); } std::string verb = "select?name=" + LLURI::escape(msg); @@ -267,6 +276,15 @@ void inventory_offer_handler(LLOfferInfo* info) // Object -> Agent Inventory Offer if (info->mFromObject && !bAutoAccept) { +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only filter if the object owner is a nearby agent + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, info->mFromID)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) + { + payload["rlv_shownames"] = TRUE; + args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "rlvanonym").getSLURLString(); + } +// [/RLVa:KB] + // Inventory Slurls don't currently work for non agent transfers, so only display the object name. args["ITEM_SLURL"] = msg; // Note: sets inventory_task_offer_callback as the callback @@ -281,6 +299,18 @@ void inventory_offer_handler(LLOfferInfo* info) } else // Agent -> Agent Inventory Offer { +// [RLVa:KB] - Checked: RLVa-2.0.1 + // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, info->mFromID)) || (!RlvUtil::isNearbyAgent(info->mFromID)) || (RlvUIEnabler::hasOpenIM(info->mFromID)) || (RlvUIEnabler::hasOpenProfile(info->mFromID)); + if (!fRlvCanShowName) + { + payload["rlv_shownames"] = TRUE; + args["NAME"] = RlvStrings::getAnonym(info->mFromName); + args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "rlvanonym").getSLURLString(); + } +// [/RLVa:KB] + p.responder = info; // Note: sets inventory_offer_callback as the callback // *TODO fix memory leak @@ -497,10 +527,24 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, // do nothing -- don't distract newbies in // Prelude with global IMs } - else if (offline == IM_ONLINE - && is_do_not_disturb - && from_id.notNull() //not a system message - && to_id.notNull()) //not global message +// [RLVa:KB] - Checked: RLVa-2.1.0 + else if ( (RlvActions::isRlvEnabled()) && (offline == IM_ONLINE) && (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) && + (message.length() > 3) && (RLV_CMD_PREFIX == message[0]) && (RlvHandler::instance().processIMQuery(from_id, message)) ) + { + // Eat the message and do nothing + } +// [/RLVa:KB] +// else if (offline == IM_ONLINE +// && is_do_not_disturb +// && from_id.notNull() //not a system message +// && to_id.notNull()) //not global message +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + else if (offline == IM_ONLINE + && is_do_not_disturb + && from_id.notNull() //not a system message + && to_id.notNull() //not global message + && RlvActions::canReceiveIM(from_id)) +// [/RLVa:KB] { // now store incoming IM in chat history @@ -570,6 +614,17 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, mute_im = true; } + +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!LLMuteList::getInstance()->isLinden(original_name) )) + { + if (!mute_im) + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } +// [/RLVa:KB] + if (!mute_im) { gIMMgr->addMessage( @@ -929,8 +984,18 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, case IM_INVENTORY_ACCEPTED: { - args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; - args["ORIGINAL_NAME"] = original_name; +// args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// args["ORIGINAL_NAME"] = original_name; +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) || (!RlvUtil::isNearbyAgent(from_id)) || (RlvUIEnabler::hasOpenProfile(from_id)) || (RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = LLSLURL("agent", from_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString(); + if (RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) + args["ORIGINAL_NAME"] = original_name; + else + args["ORIGINAL_NAME"] = RlvStrings::getAnonym(original_name); +// [/RLVa:KB] LLSD payload; payload["from_id"] = from_id; // Passing the "SESSION_NAME" to use it for IM notification logging @@ -941,7 +1006,13 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } case IM_INVENTORY_DECLINED: { - args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, from_id)) || (!RlvUtil::isNearbyAgent(from_id)) || (RlvUIEnabler::hasOpenProfile(from_id)) || (RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = LLSLURL("agent", from_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString();; +// [/RLVa:KB] LLSD payload; payload["from_id"] = from_id; LLNotificationsUtil::add("InventoryDeclined", args, payload); @@ -1003,6 +1074,25 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, LLSD query_string; query_string["owner"] = from_id; +// [RLVa:KB] - Checked: RLVa-1.2.0 + if (RlvActions::isRlvEnabled()) + { + // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) + { + query_string["rlv_shownames"] = TRUE; + + RlvUtil::filterNames(name); + chat.mFromName = name; + } + if (!RlvActions::canShowLocation()) + { + std::string::size_type idxPos = location.find('/'); + if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) + location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } + } +// [/RLVa:KB] query_string["slurl"] = location; query_string["name"] = name; if (from_group) @@ -1010,8 +1100,11 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, query_string["groupowned"] = "true"; } - chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); - chat.mText = message; +// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); +// [/SL:KB] + chat.mText = message; // Note: lie to Nearby Chat, pretending that this is NOT an IM, because // IMs from obejcts don't open IM sessions. @@ -1160,7 +1253,14 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, case IM_LURE_USER: case IM_TELEPORT_REQUEST: { - if (is_muted) + // [RLVa:KB] - Checked: RLVa-1.4.9 + // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) + bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && + ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); +// [/RLVa:KB] + + if (is_muted) { return; } @@ -1170,7 +1270,10 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else { - if (is_do_not_disturb) +// if (is_do_not_disturb) +// [RLVa:KB] - Checked: RLVa-1.4.9 + if ( (is_do_not_disturb) && (!fRlvAutoAccept) ) +// [/RLVa:KB] { send_do_not_disturb_message(gMessageSystem, from_id); } @@ -1228,8 +1331,32 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } } - LLSD args; +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (rlv_handler_t::isEnabled()) + { + if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + return; + } + + // Censor message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer/request and @showloc=n restricted + if ( (!RlvActions::canReceiveIM(from_id)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) ) + { + message = RlvStrings::getString(RLV_STRING_HIDDEN); + } + } +// [/RLVa:KB] + + LLSD args; // *TODO: Translate -> [FIRST] [LAST] (maybe) +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + args["NAME_LABEL"] = LLSLURL("agent", from_id, "completename").getSLURLString(); +// [/SL:KB] args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); args["MESSAGE"] = message; args["MATURITY_STR"] = region_access_str; @@ -1273,7 +1400,22 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, params.substitutions = args; params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>(params, from_id, false); + +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (fRlvAutoAccept) + { + if (IM_LURE_USER == dialog) + gRlvHandler.setCanCancelTp(false); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else + { + LLPostponedNotification::add<LLPostponedOfferNotification>(params, from_id, false); + } +// [/RLVa:KB] +// LLPostponedNotification::add<LLPostponedOfferNotification>(params, from_id, false); } } } @@ -1426,6 +1568,9 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, { send_do_not_disturb_message(gMessageSystem, from_id); } +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + args["NAME_LABEL"] = LLSLURL("agent", from_id, "completename").getSLURLString(); +// [/SL:KB] args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); if (add_notification) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index d5142a4496a9b2bc3e9a6c2894d80a6ba3a73f7d..4ea73ea4d953d4b88e61dd303591db4952a19228 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -69,7 +69,10 @@ #include "message.h" #include "llviewerregion.h" #include "llcorehttputil.h" - +// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] const static std::string ADHOC_NAME_SUFFIX(" Conference"); @@ -3658,6 +3661,20 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode { return; } +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + if ( (RlvActions::hasBehaviour(RLV_BHVR_RECVIM)) || (RlvActions::hasBehaviour(RLV_BHVR_RECVIMFROM)) ) + { + if (gAgent.isInGroup(session_id)) // Group chat: don't accept the invite if not an exception + { + if (!RlvActions::canReceiveIM(session_id)) + return; + } + else if (!RlvActions::canReceiveIM(from_id)) // Conference chat: don't block; censor if not an exception + { + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } + } +// [/RLVa:KB] // standard message, not from system std::string saved; diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index f78a5cc64e0c2b9a3b65a39f6e9a5517c30403f8..730e67ddac40d1fe1c0ea06a9022a5f7b7ec9dbf 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -38,6 +38,11 @@ #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llviewerobjectlist.h" // to select the requested object +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0c) +#include "rlvactions.h" +#include "rlvcommon.h" +#include "lltoolpie.h" +// [/RLVa:KB] // Linden libraries #include "llbutton.h" // setLabel(), not virtual! @@ -358,6 +363,10 @@ void LLInspectObject::updateButtons(LLSelectNode* nodep) || (parent && parent->flagHandleTouch())) { getChild<LLUICtrl>("touch_btn")->setVisible(true); +// [RLVa:KB] - Checked: RLVa-1.2.1 + if (RlvActions::isRlvEnabled()) + getChild<LLUICtrl>("touch_btn")->setEnabled(RlvActions::canTouch(object)); +// [/RLVa:KB] updateTouchLabel(nodep); } else if ( enable_object_open() ) @@ -387,6 +396,15 @@ void LLInspectObject::updateSitLabel(LLSelectNode* nodep) { sit_btn->setLabel( getString("Sit") ); } + +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + // RELEASE-RLVa: [SL-2.0.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for + if (RlvActions::isRlvEnabled()) + { + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + sit_btn->setEnabled( (pick.mObjectID.notNull()) && (RlvActions::canSit(pick.getObject(), pick.mObjectOffset)) ); + } +// [/RLVa:KB] } void LLInspectObject::updateTouchLabel(LLSelectNode* nodep) @@ -482,10 +500,15 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) // a clickable link // Objects cannot be created by a group, so use agent URL format LLUUID creator_id = nodep->mPermissions->getCreator(); - std::string creator_url = - LLSLURL("agent", creator_id, "about").getSLURLString(); +// std::string creator_url = +// LLSLURL("agent", creator_id, "about").getSLURLString(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + // Only anonymize the creator if they're also the owner or if they're a nearby avie + bool fRlvHideCreator = (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) && ((nodep->mPermissions->getOwner() == creator_id) || (RlvUtil::isNearbyAgent(creator_id))); + const std::string creator_url = LLSLURL("agent", creator_id, (!fRlvHideCreator) ? "about" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] args["[CREATOR]"] = creator_url; - + // created by one user but owned by another std::string owner_url; LLUUID owner_id; @@ -498,7 +521,11 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep) else { owner_id = nodep->mPermissions->getOwner(); - owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); +// owner_url = LLSLURL("agent", owner_id, "about").getSLURLString(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool fRlvHideOwner = (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id)); + owner_url = LLSLURL("agent", owner_id, (!fRlvHideOwner) ? "about" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] } args["[OWNER]"] = owner_url; diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index 272c8acbd5b8fc0d683b52d0af7bb00ea1c9f6cc..8fa90c5d62716d9a335703b06d020b4856eb85f4 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -35,6 +35,9 @@ #include "llui.h" #include "lluictrl.h" #include "llurlaction.h" +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) +#include "rlvhandler.h" +// [/RLVa:KB] ////////////////////////////////////////////////////////////////////////////// // LLInspectRemoteObject @@ -66,6 +69,9 @@ class LLInspectRemoteObject : public LLInspect LLUUID mOwnerID; std::string mSLurl; std::string mName; +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + bool mRlvHideNames; +// [/RLVa:KB] bool mGroupOwned; }; @@ -75,6 +81,9 @@ LLInspectRemoteObject::LLInspectRemoteObject(const LLSD& sd) : mOwnerID(NULL), mSLurl(""), mName(""), +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + mRlvHideNames(false), +// [/RLVa:KB] mGroupOwned(false) { } @@ -107,6 +116,10 @@ void LLInspectRemoteObject::onOpen(const LLSD& data) mOwnerID = data["owner_id"].asUUID(); mGroupOwned = data["group_owned"].asBoolean(); mSLurl = data["slurl"].asString(); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + if (data.has("rlv_shownames")) + mRlvHideNames = data["rlv_shownames"].asBoolean(); +// [/RLVa:KB] // update the inspector with the current object state update(); @@ -160,7 +173,10 @@ void LLInspectRemoteObject::update() } else { - owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); +// owner = LLSLURL("agent", mOwnerID, "about").getSLURLString(); +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + owner = LLSLURL("agent", mOwnerID, (!mRlvHideNames) ? "about" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] } } else @@ -182,6 +198,14 @@ void LLInspectRemoteObject::update() // disable the Block button if we don't have the object ID (will this ever happen?) getChild<LLUICtrl>("block_btn")->setEnabled(!mObjectID.isNull() && !LLMuteList::getInstance()->isMuted(mObjectID)); + +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if ( (rlv_handler_t::isEnabled()) && (RlvStrings::getString(RLV_STRING_HIDDEN_REGION) == mSLurl) ) + { + getChild<LLUICtrl>("object_slurl")->setValue(mSLurl); + getChild<LLUICtrl>("map_btn")->setEnabled(false); + } +// [/RLVa:KB] } ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 36784ce3f9ace5c2f2b37b7feddfbc69178abe81..f5d30034ddc113bde9b6e8d8036879bf74e27430 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -81,6 +81,11 @@ #include "llwearableitemslist.h" #include "lllandmarkactions.h" #include "llpanellandmarks.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include <boost/shared_ptr.hpp> @@ -911,6 +916,20 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + if (rlv_handler_t::isEnabled()) + { + const LLInventoryObject* pItem = getInventoryObject(); + if ( (pItem) && + ( ((LLAssetType::AT_NOTECARD == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE))) || + ((LLAssetType::AT_LSL_TEXT == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT))) || + ((LLAssetType::AT_TEXTURE == pItem->getType()) && (!RlvActions::canPreviewTextures())))) + { + disabled_items.push_back(std::string("Open")); + } + } +// [/RLVa:KB] + getClipboardEntries(true, items, disabled_items, flags); } addLinkReplaceMenuOption(items, disabled_items); @@ -1995,6 +2014,13 @@ BOOL LLItemBridge::isItemRenameable() const return FALSE; } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && (!RlvFolderLocks::instance().canRenameItem(mUUID)) ) + { + return FALSE; + } +// [/RLVa:KB] + return (item->getPermissions().allowModifyBy(gAgent.getID())); } return FALSE; @@ -2669,6 +2695,14 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } + +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + if ( (is_movable) && (rlv_handler_t::isEnabled()) && (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) ) + { + is_movable = RlvFolderLocks::instance().canMoveFolder(cat_id, mUUID); + } +// [/RLVa:KB] + // //-------------------------------------------------------------------------------- @@ -3727,6 +3761,15 @@ void LLFolderBridge::perform_pasteFromClipboard() LLNotificationsUtil::add("StockPasteFailed", subs); return; } + +// [RLVa:KB] - Checked: RLVa-2.1.0 + if ( ((item) && (!RlvActions::canPasteInventory(item, dest_folder))) || ((cat) && (!RlvActions::canPasteInventory(cat, dest_folder))) ) + { + RlvActions::notifyBlocked(RLV_STRING_BLOCKED_INVFOLDER); + return; + } +// [/RLVa:KB] + } } @@ -4230,6 +4273,9 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); // BAP change once we're no longer treating regular categories as ensembles. const bool is_agent_inventory = isAgentInventory(); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-2.4) + const bool is_outfit = (type == LLFolderType::FT_OUTFIT); +// [/SL:KB] // Only enable calling-card related options for non-system folders. if (!is_system_folder && is_agent_inventory) @@ -4281,10 +4327,21 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& disabled_items.push_back(std::string("Remove From Outfit")); } } - if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) +// if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-2.4) + if ( ((is_outfit) && (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))) || + ((!is_outfit) && (gAgentWearables.isCOFChangeInProgress())) ) +// [/SL:KB] { disabled_items.push_back(std::string("Replace Outfit")); } +// [RLVa:KB] - Checked: RLVa-2.0.3 + // Block "Replace Current Outfit" if the user can't wear the new folder + if ( (RlvActions::isRlvEnabled()) && (RlvFolderLocks::instance().isLockedFolder(mUUID, RLV_LOCK_ADD)) ) + { + disabled_items.push_back(std::string("Replace Outfit")); + } +// [/RLVa:KB] if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) { disabled_items.push_back(std::string("Add To Outfit")); @@ -4976,6 +5033,24 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { is_movable = FALSE; } + +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && (is_movable) ) + { + if (move_is_into_current_outfit) + { + // RELEASE-RLVa: [RLVa-1.3.0] Keep sync'ed with code below => LLAppearanceMgr::wearItemOnAvatar() with "replace == true" + const LLViewerInventoryItem* pItem = dynamic_cast<const LLViewerInventoryItem*>(inv_item); + is_movable = rlvPredCanWearItem(pItem, RLV_WEAR_REPLACE); + } + if (is_movable) + { + is_movable = (!RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) || + (RlvFolderLocks::instance().canMoveItem(inv_item->getUUID(), mUUID)); + } + } +// [/RLVa:KB] + if (move_is_into_trash) { is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); @@ -5412,6 +5487,13 @@ bool LLTextureBridge::canSaveTexture(void) return false; } +// [RLVa:KB] - Checked: RLVa-2.2 (@viewtexture) + if (!RlvActions::canPreviewTextures()) + { + return false; + } +// [/RLVa:KB] + const LLViewerInventoryItem *item = model->getItem(mUUID); if (item) { @@ -5792,6 +5874,16 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act { callingcard_name = av_name.getCompleteName(); } + +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if (!RlvActions::canStartIM(item->getCreatorUUID())) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", item->getCreatorUUID(), "completename").getSLURLString())); + return; + } +// [/RLVa:KB] + LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID()); if (session_id != LLUUID::null) { @@ -6343,7 +6435,11 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) else if(item && item->isFinished()) { // must be in library. copy it to our inventory and put it on. - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0)); +// LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0)); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2013-02-04 (Catznip-3.4) + // "Wear" from inventory replaces, so library items should too + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, true)); +// [/SL;KB] copy_inventory_item( gAgent.getID(), item->getPermissions().getOwner(), @@ -6400,6 +6496,21 @@ std::string LLObjectBridge::getLabelSuffix() const void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1) + // If no attachment point was specified, try looking it up from the item name + static LLCachedControl<bool> fRlvDeprecateAttachPt(gSavedSettings, "RLVaDebugDeprecateExplicitPoint", false); + if ( (rlv_handler_t::isEnabled()) && (!fRlvDeprecateAttachPt) && + (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + { + attachment = RlvAttachPtLookup::getAttachPoint(item); + } + + if ( (RlvActions::isRlvEnabled()) && (!rlvPredCanWearItem(item, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + return; + } +// [/RLVa:KB] + const LLUUID& item_id = item->getLinkedUUID(); // Check for duplicate request. @@ -6432,10 +6543,24 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach if (replace && (attachment && attachment->getNumObjects() > 0)) { +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1) + // Block if we can't "replace wear" what's currently there + if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0) ) + { + return; + } +// [/RLVa:KB] LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez); } else { +// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0) + // Block wearing anything on a non-attachable attachment point + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) ) + { + return; + } +// [/RLVa:KB] LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } } @@ -6509,6 +6634,10 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Detach From Yourself")); +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canDetach(item)) ) + disabled_items.push_back(std::string("Detach From Yourself")); +// [/RLVa:KB] } else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder()) { @@ -6527,6 +6656,17 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Attach To")); disabled_items.push_back(std::string("Attach To HUD")); } +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + else if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(item); + if ((eWearMask & RLV_WEAR_REPLACE) == 0) + disabled_items.push_back(std::string("Wearable And Object Wear")); + if ((eWearMask & RLV_WEAR_ADD) == 0) + disabled_items.push_back(std::string("Wearable Add")); + } +// [/RLVa:KB] + LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE); LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE); if (attach_menu @@ -6770,18 +6910,36 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Add")); +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Added: RLVa-1.2.0c + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) + disabled_items.push_back(std::string("Take Off")); +// [/RLVa:KB] } else { items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Take Off")); disabled_items.push_back(std::string("Wearable Edit")); + +// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g + if (rlv_handler_t::isEnabled()) + { + ERlvWearMask eWearMask = gRlvWearableLocks.canWear(item); + if ((eWearMask & RLV_WEAR_REPLACE) == 0) + disabled_items.push_back(std::string("Wearable And Object Wear")); + if ((eWearMask & RLV_WEAR_ADD) == 0) + disabled_items.push_back(std::string("Wearable Add")); + } +// [/RLVa:KB] } if (LLWearableType::getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); - if (!gAgentWearables.canAddWearable(mWearableType)) +// if (!gAgentWearables.canAddWearable(mWearableType)) +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e + if ( (!gAgentWearables.canAddWearable(mWearableType)) || (gAgentWearables.getWearableFromAssetID(item->getAssetUUID())) ) +// [/SL:KB] { disabled_items.push_back(std::string("Wearable Add")); } @@ -6842,56 +7000,56 @@ void LLWearableBridge::wearAddOnAvatar() } // static -void LLWearableBridge::onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) -{ - LLUUID* item_id = (LLUUID*) userdata; - if(wearable) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); - if(item) - { - if(item->getAssetUUID() == wearable->getAssetID()) - { - gAgentWearables.setWearableItem(item, wearable); - gInventory.notifyObservers(); - //self->getFolderItem()->refreshFromRoot(); - } - else - { - LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; - } - } - } - delete item_id; -} +//void LLWearableBridge::onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) +//{ +// LLUUID* item_id = (LLUUID*) userdata; +// if(wearable) +// { +// LLViewerInventoryItem* item = NULL; +// item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); +// if(item) +// { +// if(item->getAssetUUID() == wearable->getAssetID()) +// { +// gAgentWearables.setWearableItem(item, wearable); +// gInventory.notifyObservers(); +// //self->getFolderItem()->refreshFromRoot(); +// } +// else +// { +// LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; +// } +// } +// } +// delete item_id; +//} // static // BAP remove the "add" code path once everything is fully COF-ified. -void LLWearableBridge::onWearAddOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) -{ - LLUUID* item_id = (LLUUID*) userdata; - if(wearable) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); - if(item) - { - if(item->getAssetUUID() == wearable->getAssetID()) - { - bool do_append = true; - gAgentWearables.setWearableItem(item, wearable, do_append); - gInventory.notifyObservers(); - //self->getFolderItem()->refreshFromRoot(); - } - else - { - LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; - } - } - } - delete item_id; -} +//void LLWearableBridge::onWearAddOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) +//{ +// LLUUID* item_id = (LLUUID*) userdata; +// if(wearable) +// { +// LLViewerInventoryItem* item = NULL; +// item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); +// if(item) +// { +// if(item->getAssetUUID() == wearable->getAssetID()) +// { +// bool do_append = true; +// gAgentWearables.setWearableItem(item, wearable, do_append); +// gInventory.notifyObservers(); +// //self->getFolderItem()->refreshFromRoot(); +// } +// else +// { +// LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; +// } +// } +// } +// delete item_id; +//} // static BOOL LLWearableBridge::canEditOnAvatar(void* user_data) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 0823cf8b52cf35d24cfe56048925d3a66c7aad0d..eee62e5ab022b934f0f3efad1f6e88cae8f117bd 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -546,10 +546,10 @@ class LLWearableBridge : public LLItemBridge static void onWearOnAvatar( void* userdata ); // Access to wearOnAvatar() from menu static BOOL canWearOnAvatar( void* userdata ); - static void onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata ); +// static void onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata ); void wearOnAvatar(); - static void onWearAddOnAvatarArrived( LLViewerWearable* wearable, void* userdata ); +// static void onWearAddOnAvatarArrived( LLViewerWearable* wearable, void* userdata ); void wearAddOnAvatar(); static BOOL canEditOnAvatar( void* userdata ); // Access to editOnAvatar() from menu diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 030c9670191193682ac1c458f118b578d2eee27a..4fcbd3aad3a632a943803cea8c7594f54e044b0f 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -85,6 +85,10 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwearablelist.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] #include <boost/foreach.hpp> @@ -529,10 +533,11 @@ BOOL get_is_item_worn(const LLUUID& id) return FALSE; // Consider the item as worn if it has links in COF. - if (LLAppearanceMgr::instance().isLinkedInCOF(id)) - { - return TRUE; - } +// [SL:KB] - The code below causes problems across the board so it really just needs to go +// if (LLAppearanceMgr::instance().isLinkedInCOF(id)) +// { +// return TRUE; +// } switch(item->getType()) { @@ -643,6 +648,14 @@ BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) } } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (RlvActions::isRlvEnabled()) && + (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveItem(id)) ) + { + return FALSE; + } +// [/RLVa:KB] + const LLInventoryObject *obj = model->getItem(id); if (obj && obj->getIsLinkType()) { @@ -671,6 +684,14 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) return FALSE; } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( ((RlvActions::isRlvEnabled()) && + (RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) && (!RlvFolderLocks::instance().canRemoveFolder(id))) ) + { + return FALSE; + } +// [/RLVa:KB] + if (!isAgentAvatarValid()) return FALSE; const LLInventoryCategory* category = model->getCategory(id); @@ -706,6 +727,13 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) return FALSE; } +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (RlvActions::isRlvEnabled()) && (model == &gInventory) && (!RlvFolderLocks::instance().canRenameFolder(id)) ) + { + return FALSE; + } +// [/RLVa:KB] + LLViewerInventoryCategory* cat = model->getCategory(id); if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c49d61df31128c59ea8bd066868057e6fdc5a560..3e80368b7c918908feb29c3fc72b35301468dd01 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -60,6 +60,10 @@ #include "bufferarray.h" #include "bufferstream.h" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] //#define DIFF_INVENTORY_FILES #ifdef DIFF_INVENTORY_FILES @@ -758,11 +762,19 @@ void LLInventoryModel::collectDescendents(const LLUUID& id, collectDescendentsIf(id, cats, items, include_trash, always); } +//void LLInventoryModel::collectDescendentsIf(const LLUUID& id, +// cat_array_t& cats, +// item_array_t& items, +// BOOL include_trash, +// LLInventoryCollectFunctor& add) +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t& cats, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add) + LLInventoryCollectFunctor& add, + bool follow_folder_links) +// [/RLVa:KB] { // Start with categories if(!include_trash) @@ -782,7 +794,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, { cats.push_back(cat); } - collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) + collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add, follow_folder_links); +// [/RLVa:KB] +// collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); } } @@ -802,6 +817,44 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } } + +// [RLVa:KB] - Checked: 2010-09-30 (RLVa-1.2.1d) | Added: RLVa-1.2.1d + // The problem is that we want some way for the functor to know that it's being asked to decide on a folder link + // but it won't know that until after it has encountered the folder link item (which doesn't happen until *after* + // it has already collected all items from it the way the code was originally laid out) + // This breaks the "finish collecting all folders before collecting items (top to bottom and then bottom to top)" + // assumption but no functor is (currently) relying on it (and likely never should since it's an implementation detail?) + // [Only LLAppearanceMgr actually ever passes in 'follow_folder_links == TRUE'] + // Follow folder links recursively. Currently never goes more + // than one level deep (for current outfit support) + // Note: if making it fully recursive, need more checking against infinite loops. + if (follow_folder_links && item_array) + { + S32 count = item_array->size(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->at(i); + if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) + { + LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); + if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT) + // BAP - was + // LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType())) + // Change back once ensemble typing is in place. + { + if(add(linked_cat,NULL)) + { + // BAP should this be added here? May not + // matter if it's only being used in current + // outfit traversal. + cats.push_back(LLPointer<LLViewerInventoryCategory>(linked_cat)); + } + collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, false); + } + } + } + } +// [/RLVa:KB] } void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) @@ -3098,6 +3151,14 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" " not found: " << item_id << LL_ENDL; } + +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-0.2.0e + if (rlv_handler_t::isEnabled()) + { + RlvAttachmentLockWatchdog::instance().onSavedAssetIntoInventory(item_id); + } +// [/RLVa:KB] + if(gViewerWindow) { gViewerWindow->getWindow()->decBusyCount(); @@ -3159,6 +3220,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { if(tfolder->getParentUUID() == folderp->getParentUUID()) { +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + // NOTE-RLVa: not sure if this is a hack or a bug-fix :o + // -> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain + // the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the + // viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server + // -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues + // -> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem + // to be any way to accomplish that either *sighs* + if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) && + ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) ) + { + tfolder->rename(folderp->getName()); + } +// [/RLVa:KB] update[tfolder->getParentUUID()]; } else diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a4326aaeed9708a41e836f05f4f6798f96ed89d3..bd31b02a757a2c5eed8acf05e7cb97a3953d7f9a 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -249,11 +249,19 @@ class LLInventoryModel cat_array_t& categories, item_array_t& items, BOOL include_trash); +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) void collectDescendentsIf(const LLUUID& id, cat_array_t& categories, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add); + LLInventoryCollectFunctor& add, + bool follow_folder_links = false); +// [/RLVa:KB] +// void collectDescendentsIf(const LLUUID& id, +// cat_array_t& categories, +// item_array_t& items, +// BOOL include_trash, +// LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 6f461673ee0580752b9b88a9b35aae8e057e97f0..e385483b1001ccf0d62f27364a5148158a42ee2a 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -50,6 +50,10 @@ #include "llviewerattachmenu.h" #include "llviewerfoldertype.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel"); @@ -1237,7 +1241,11 @@ bool LLInventoryPanel::beginIMSession() std::string name; std::vector<LLUUID> members; - EInstantMessage type = IM_SESSION_CONFERENCE_START; +// EInstantMessage type = IM_SESSION_CONFERENCE_START; + +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + bool fRlvCanStartIM = true; +// [/RLVa:KB] std::set<LLFolderViewItem*>::const_iterator iter; for (iter = selected_items.begin(); iter != selected_items.end(); iter++) @@ -1276,10 +1284,17 @@ bool LLInventoryPanel::beginIMSession() for(S32 i = 0; i < count; ++i) { id = item_array.at(i)->getCreatorUUID(); - if(at.isBuddyOnline(id)) +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if ( (at.isBuddyOnline(id)) && (members.end() == std::find(members.begin(), members.end(), id)) ) { + fRlvCanStartIM &= RlvActions::canStartIM(id); members.push_back(id); } +// [/RLVa:KB] +// if(at.isBuddyOnline(id)) +// { +// members.push_back(id); +// } } } } @@ -1296,10 +1311,17 @@ bool LLInventoryPanel::beginIMSession() LLAvatarTracker& at = LLAvatarTracker::instance(); LLUUID id = inv_item->getCreatorUUID(); - if(at.isBuddyOnline(id)) +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if ( (at.isBuddyOnline(id)) && (members.end() == std::find(members.begin(), members.end(), id)) ) { + fRlvCanStartIM &= RlvActions::canStartIM(id); members.push_back(id); } +// [/RLVa:KB] +// if(at.isBuddyOnline(id)) +// { +// members.push_back(id); +// } } } //if IT_CALLINGCARD } //if !IT_CATEGORY @@ -1309,16 +1331,34 @@ bool LLInventoryPanel::beginIMSession() // the session_id is randomly generated UUID which will be replaced later // with a server side generated number +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if (!fRlvCanStartIM) + { + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return true; + } +// [/RLVa:KB] + if (name.empty()) { name = LLTrans::getString("conference-title"); } - LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); - if (session_id != LLUUID::null) +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h + if (!members.empty()) { - LLFloaterIMContainer::getInstance()->showConversation(session_id); + if (members.size() > 1) + LLAvatarActions::startConference(members); + else + LLAvatarActions::startIM(members[0]); } +// [/RLVa:KB] +// LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); +// if (session_id != LLUUID::null) +// { +// LLFloaterIMContainer::getInstance()->showConversation(session_id); +// } return true; } @@ -1469,8 +1509,11 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) active_inv_floaterp->setMinimized(FALSE); } } - else if (auto_open) +// else if (auto_open) +// [RLVa:KB] - Checked: 2012-05-15 (RLVa-1.4.6) + else if ( (auto_open) && (LLFloaterReg::canShowInstance(floater_inventory->getInstanceName())) ) { +// [/RLVa:KB] floater_inventory->openFloater(); res = inventory_panel->getActivePanel(); diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 802e4941e634c6137f7faee131054389ac7b7ce1..7ea63f7930e445162b657727f18f1adfc5698bfc 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -63,6 +63,9 @@ #include "llviewermenu.h" #include "llurllineeditorctrl.h" #include "llagentui.h" +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] #include "llmenuoptionpathfindingrebakenavmesh.h" #include "llpathfindingmanager.h" @@ -633,16 +636,31 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent void LLLocationInputCtrl::onInfoButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); } void LLLocationInputCtrl::onForSaleButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + handle_buy_land(); } void LLLocationInputCtrl::onAddLandmarkButtonClicked() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); // Landmark exists, open it for preview and edit if(landmark && landmark->getUUID().notNull()) @@ -770,6 +788,10 @@ void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) void LLLocationInputCtrl::refresh() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + mInfoBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] + refreshLocation(); // update location string refreshParcelIcons(); updateAddLandmarkButton(); // indicate whether current parcel has been landmarked @@ -1047,6 +1069,9 @@ void LLLocationInputCtrl::enableAddLandmarkButton(bool val) // depending on whether current parcel has been landmarked. void LLLocationInputCtrl::updateAddLandmarkButton() { +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + mAddLandmarkBtn->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark()); } void LLLocationInputCtrl::updateAddLandmarkTooltip() @@ -1076,6 +1101,9 @@ void LLLocationInputCtrl::updateContextMenu(){ { landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); } +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + landmarkItem->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] } } void LLLocationInputCtrl::updateWidgetlayout() @@ -1129,17 +1157,23 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata) } else if (item == "landmark") { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - - if(!landmark) +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.4.5) | Added: RLVa-1.2.0 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); - } - else - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); - +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + + if(!landmark) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); + } +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d } +// [/RLVa:KB] } else if (item == "cut") { diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index da71bab6c1bddc09030ae4f1588f97da072e98b7..1c4adb9e8fc5810facf74d1bead63311a9e1616c 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -109,6 +109,10 @@ class LLLocationInputCtrl LLLineEditor* getTextEntry() const { return mTextEntry; } void handleLoginComplete(); +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) + void refresh(); +// [/RLVa:KB] + private: enum EParcelIcon @@ -135,7 +139,7 @@ class LLLocationInputCtrl * depending on whether current parcel has been landmarked. */ void enableAddLandmarkButton(bool val); - void refresh(); +// void refresh(); void refreshLocation(); void refreshParcelIcons(); // Refresh the value in the health percentage text field diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 9248c160c66cca92b2b839a9b6ff31699537dbfe..e8315d5e66044e61ca15dcb9845b476c4f13e130 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -62,6 +62,9 @@ #include "pipeline.h" #include "llviewershadermgr.h" #include "lltrans.h" +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) +#include "rlvhandler.h" +// [/RLVa:KB] const S32 NUM_AXES = 3; const S32 MOUSE_DRAG_SLOP = 2; // pixels diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 54409a69943fb201bec596cfad43d18d656fefa5..ee8b3da6b07b5ec3ae14e81fb4b1f1656abc84e1 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -50,6 +50,9 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lltooltip.h" +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) +#include "rlvactions.h" +// [/RLVa:KB] // // Constants @@ -140,7 +143,10 @@ BOOL LLFloaterMove::postBuild() initMovementMode(); - gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus); +// gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + gAgent.addParcelChangedCallback(LLFloaterMove::sUpdateMovementStatus); +// [/RLVa:KB] return TRUE; } @@ -325,23 +331,32 @@ void LLFloaterMove::setMovementMode(const EMovementMode mode) { case MM_RUN: gAgent.setAlwaysRun(); - gAgent.setRunning(); +// gAgent.setRunning(); break; case MM_WALK: gAgent.clearAlwaysRun(); - gAgent.clearRunning(); +// gAgent.clearRunning(); break; default: //do nothing for other modes (MM_FLY) break; } // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); - - updateButtonsWithMovementMode(mode); +// gAgent.sendWalkRun(gAgent.getAlwaysRun()); +// +// updateButtonsWithMovementMode(mode); +// +// bool bHideModeButtons = MM_FLY == mode +// || (isAgentAvatarValid() && gAgentAvatarp->isSitting()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + // Running may have been restricted so update walk-vs-run from the agent's actual running state + if ( (MM_WALK == mode) || (MM_RUN == mode) ) + mCurrentMode = (gAgent.getRunning()) ? MM_RUN : MM_WALK; - bool bHideModeButtons = MM_FLY == mode - || (isAgentAvatarValid() && gAgentAvatarp->isSitting()); + updateButtonsWithMovementMode(mCurrentMode); + + bool bHideModeButtons = (MM_FLY == mCurrentMode) || (isAgentAvatarValid() && gAgentAvatarp->isSitting()); +// [/RLVa:KB] showModeButtons(!bHideModeButtons); @@ -444,12 +459,23 @@ void LLFloaterMove::setModeTitle(const EMovementMode mode) } //static -void LLFloaterMove::sUpdateFlyingStatus() +//void LLFloaterMove::sUpdateFlyingStatus() +//{ +// LLFloaterMove *floater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); +// if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); +// +//} +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a +void LLFloaterMove::sUpdateMovementStatus() { - LLFloaterMove *floater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); - if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); - + LLFloaterMove* pFloater = LLFloaterReg::findTypedInstance<LLFloaterMove>("moveview"); + if (pFloater) + { + pFloater->mModeControlButtonMap[MM_RUN]->setEnabled(!RlvActions::hasBehaviour(RLV_BHVR_ALWAYSRUN)); + pFloater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); + } } +// [/RLVa:KB] void LLFloaterMove::showModeButtons(BOOL bShow) { @@ -489,7 +515,10 @@ void LLFloaterMove::onOpen(const LLSD& key) showModeButtons(FALSE); } - sUpdateFlyingStatus(); +// sUpdateFlyingStatus(); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + sUpdateMovementStatus(); +// [/RLVa:KB] } void LLFloaterMove::setModeButtonToggleState(const EMovementMode mode) @@ -682,10 +711,17 @@ LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel() void LLPanelStandStopFlying::onStandButtonClick() { - LLFirstUse::sit(false); +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canStand()) ) + { + LLFirstUse::sit(false); - LLSelectMgr::getInstance()->deselectAllForStandingUp(); - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + LLSelectMgr::getInstance()->deselectAllForStandingUp(); + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + } +// [/RLVa:KB] +// LLSelectMgr::getInstance()->deselectAllForStandingUp(); +// gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); setFocus(FALSE); } diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index e8b9a6fdb20fe94b8b9f0c8fdea7e7d28089b047..f8a14dba1ede34593c863dce928f54cf4ebfea8a 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -59,7 +59,10 @@ class LLFloaterMove static void enableInstance(); /*virtual*/ void onOpen(const LLSD& key); - static void sUpdateFlyingStatus(); +// static void sUpdateFlyingStatus(); +// [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + static void sUpdateMovementStatus(); +// [/RLVa:KB] protected: void turnLeft(); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 179c64b5c572d5882e499d7211340af28464f15d..b68baf53a8d82534270c6de2a85195e6bb16ff08 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -701,6 +701,15 @@ void LLNavigationBar::resizeLayoutPanel() nav_bar_rect.setLeftTopAndSize(nav_bar_rect.mLeft, nav_bar_rect.mTop, nav_panel_width, nav_bar_rect.getHeight()); mNavigationPanel->handleReshape(nav_bar_rect,true); } + +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) +void LLNavigationBar::refreshLocationCtrl() +{ + if (mCmbLocation) + mCmbLocation->refresh(); +} +// [/RLVa:KB] + void LLNavigationBar::invokeSearch(std::string search_text) { LLFloaterReg::showInstance("search", LLSD().with("category", "all").with("query", LLSD(search_text))); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index a44c6dd6997e315dd6722579861276ac8b3d8896..997c7677cd05556052fe2941d2bf5796dd2cb7fa 100755 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -103,6 +103,9 @@ class LLNavigationBar int getDefNavBarHeight(); int getDefFavBarHeight(); +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) + void refreshLocationCtrl(); +// [/RLVa:KB] private: // the distance between navigation panel and favorites panel in pixels const static S32 FAVBAR_TOP_PADDING = 10; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 112da556825647b5d5d1ed65cd2119c8f576b1e2..73b7ca55036bdf7d72c7b3489646a49cd4099319 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -60,6 +60,10 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llworldmapview.h" // shared draw code +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map"); @@ -350,7 +354,10 @@ void LLNetMap::draw() pos_map = globalPosToView(positions[i]); - bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, uuid)); +// [/RLVa:KB] +// bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; @@ -602,11 +609,20 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) // If the cursor is near an avatar on the minimap, a mini-inspector will be // shown for the avatar, instead of the normal map tooltip. - if (handleToolTipAgent(mClosestAgentToCursor)) +// if (handleToolTipAgent(mClosestAgentToCursor)) +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool fRlvCanShowName = (mClosestAgentToCursor.notNull()) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mClosestAgentToCursor)); + if ( (fRlvCanShowName) && (handleToolTipAgent(mClosestAgentToCursor)) ) +// [/RLVa:KB] { return TRUE; } +// [RLVa:KB] - Checked: RLVa-1.2.2 + LLStringUtil::format_map_t args; LLAvatarName avName; + args["[AGENT]"] = ( (!fRlvCanShowName) && (mClosestAgentToCursor.notNull()) && (LLAvatarNameCache::get(mClosestAgentToCursor, &avName)) ) ? RlvStrings::getAnonym(avName) + "\n" : ""; +// [/RLVa:KB] + LLRect sticky_rect; std::string region_name; LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); @@ -618,14 +634,17 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP; sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP; - region_name = region->getName(); +// region_name = region->getName(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + region_name = (RlvActions::canShowLocation()) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION); +// [/RLVa:KB] if (!region_name.empty()) { region_name += "\n"; } } - LLStringUtil::format_map_t args; +// LLStringUtil::format_map_t args; args["[REGION]"] = region_name; std::string msg = mToolTipMsg; LLStringUtil::format(msg, args); diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp index 58a9b01a45944df8e232110ac02650f7eee0a33d..1058c3836cbf1fa5b589dc550c3ae877fadb65e9 100644 --- a/indra/newview/llnotificationalerthandler.cpp +++ b/indra/newview/llnotificationalerthandler.cpp @@ -38,6 +38,10 @@ #include "lltoastalertpanel.h" +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) +#include "rlvactions.h" +// [/RLVa:KB] + using namespace LLNotificationsUI; //-------------------------------------------------------------------------- @@ -88,8 +92,19 @@ bool LLAlertHandler::processNotification(const LLNotificationPtr& notification) LLUUID from_id = notification->getPayload()["from_id"]; - // firstly create session... - LLHandlerUtil::spawnIMSession(name, from_id); +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + // Don't spawn an IM session for non-chat related events: + // - LLHandlerUtil::logToIMP2P() below will still be called with to_file_only == false + // - LLHandlerUtil::logToIM() will eventually be called as a result and without an open IM session it will log the + // same message as it would for an open session whereas to_file_only == true would take a different code path + if (RlvActions::canStartIM(from_id)) + { +// [/RLVa:KB] + // firstly create session... + LLHandlerUtil::spawnIMSession(name, from_id); +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + } +// [/RLVa:KB] // ...then log message to have IM Well notified about new message LLHandlerUtil::logToIMP2P(notification); diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 52c5234137f36f2eb2a4862178b5e61c6a027209..c044c9d696e2c072ed3b2ac8f46ecdcace2bfc6e 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -334,16 +334,23 @@ class LLHandlerUtil */ static void updateIMFLoaterMesages(const LLUUID& session_id); - /** - * Updates messages of visible IM floater. - */ - static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification); +// /** +// * Updates messages of visible IM floater. +// */ +// static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification); /** * Decrements counter of IM messages. */ static void decIMMesageCounter(const LLNotificationPtr& notification); +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + /** + * Checks whether the user has opted to embed (certain) notifications in IM sessions + */ + static bool canEmbedNotificationInIM(const LLNotificationPtr& notification); +// [/SL:KB] + }; } diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 9a3f1a853a9f3066ca11193c8d4b7fb9b855411b..1e1f243653fd8739537ce71ded9e0a5c38b6e03e 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -293,15 +293,15 @@ void LLHandlerUtil::updateIMFLoaterMesages(const LLUUID& session_id) } } -// static -void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification) -{ - const std::string name = LLHandlerUtil::getSubstitutionName(notification); - LLUUID from_id = notification->getPayload()["from_id"]; - LLUUID session_id = spawnIMSession(name, from_id); - - updateIMFLoaterMesages(session_id); -} +//// static +//void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification) +//{ +// const std::string name = LLHandlerUtil::getSubstitutionName(notification); +// LLUUID from_id = notification->getPayload()["from_id"]; +// LLUUID session_id = spawnIMSession(name, from_id); +// +// updateIMFLoaterMesages(session_id); +//} // static void LLHandlerUtil::decIMMesageCounter(const LLNotificationPtr& notification) diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 14d25d81582685e199990be050608558645264c4..d4898bb497deb97d68579e5f964eefb4110e0001 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -36,6 +36,9 @@ #include "llscriptfloater.h" #include "llimview.h" #include "llnotificationsutil.h" +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) +#include "rlvactions.h" +// [/RLVa:KB] using namespace LLNotificationsUI; @@ -112,9 +115,21 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) } } - LLHandlerUtil::spawnIMSession(name, from_id); - LLHandlerUtil::addNotifPanelToIM(notification); - +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + // Don't spawn an IM session for non-chat related events + if (RlvActions::canStartIM(from_id)) + { +// [/RLVa:KB] + LLHandlerUtil::spawnIMSession(name, from_id); + LLHandlerUtil::addNotifPanelToIM(notification); +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + } + else + { + // Since we didn't add this notification to an IM session we want it to get routed to the notification syswell + add_notif_to_im = false; + } +// [/RLVa:KB] } if (!notification->canShowToast()) @@ -182,9 +197,18 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification) } else { - if (notification->canLogToIM() - && notification->hasFormElements() - && !LLHandlerUtil::isIMFloaterOpened(notification)) +// if (notification->canLogToIM() +// && notification->hasFormElements() +// && !LLHandlerUtil::isIMFloaterOpened(notification)) +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + // The above test won't necessarily tell us whether the notification went into an IM or to the notification syswell + // -> the one and only time we need to decrease the unread IM count is when we've clicked any of the buttons on the *toast* + // -> since LLIMFloater::updateMessages() hides the toast when we open the IM (which resets the unread count to 0) we should + // *only* decrease the unread IM count if there's a visible toast since the unread count will be at 0 otherwise anyway + LLScreenChannel* pChannel = dynamic_cast<LLScreenChannel*>(mChannel.get()); + LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL; + if ( (pToast) && (!pToast->getCanBeStored()) ) +// [/SL:KB] { LLHandlerUtil::decIMMesageCounter(notification); } diff --git a/indra/newview/llpanelappearancetab.cpp b/indra/newview/llpanelappearancetab.cpp index 8fa8867c696fca1358eda2c37a006b8899bac65c..fdb331163b2c8e1487c143a4ec8657485cace9ce 100644 --- a/indra/newview/llpanelappearancetab.cpp +++ b/indra/newview/llpanelappearancetab.cpp @@ -32,6 +32,10 @@ #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llviewerinventory.h" +// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7) +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] //virtual bool LLPanelAppearanceTab::canTakeOffSelected() @@ -46,6 +50,11 @@ bool LLPanelAppearanceTab::canTakeOffSelected() LLViewerInventoryItem* item = gInventory.getItem(*it); if (!item) continue; +// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7) + if ( (rlv_handler_t::isEnabled()) && (rlvPredCanNotRemoveItem(item)) ) + return false; +// [/RLVa:KB] + if (is_worn(NULL, item)) return true; } return false; diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 451f41cd3bfe6dfa756ac9ea2f95ad97ffacacf9..07693bda99331b755bded0756e33e7dc256f6696 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -60,6 +60,10 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llfloaterperms.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] // // Imported globals @@ -119,6 +123,25 @@ void LLPanelContents::getState(LLViewerObject *objectp ) && ( objectp->permYouOwner() || ( !group_id.isNull() && gAgent.isInGroup(group_id) ))); // solves SL-23488 BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (editable) ) + { + // Don't allow creation of new scripts if it's non-detachable + if (objectp->isAttachment()) + editable = !gRlvAttachmentLocks.isLockedAttachment(objectp->getRootEdit()); + + // Don't allow creation of new scripts if we're @unsit=n or @sittp=n restricted and we're sitting on the selection + if ( (editable) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) ) + { + // Only check the first (non-)root object because nothing else would result in enabling the button (see below) + LLViewerObject* pObj = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(TRUE); + + editable = + (pObj) && (isAgentAvatarValid()) && ((!gAgentAvatarp->isSitting()) || (gAgentAvatarp->getRoot() != pObj->getRootEdit())); + } + } +// [/RLVa:KB] + // Edit script button - ok if object is editable and there's an unambiguous destination for the object. getChildView("button new script")->setEnabled( editable && @@ -162,6 +185,21 @@ void LLPanelContents::onClickNewScript(void *userdata) LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok); if(object) { +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if (rlv_handler_t::isEnabled()) // Fallback code [see LLPanelContents::getState()] + { + if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) + { + return; // Disallow creating new scripts in a locked attachment + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) ) + return; // .. or in a linkset the avie is sitting on under @unsit=n/@sittp=n + } + } +// [/RLVa:KB] + LLPermissions perm; perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp index acdb16f43291807995eaeb9dfb2f99a6082c14f0..49b96fb10da4df5f70801cb9239ddc48af153a84 100644 --- a/indra/newview/llpanelland.cpp +++ b/indra/newview/llpanelland.cpp @@ -44,6 +44,10 @@ #include "lluictrlfactory.h" +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] + LLPanelLandSelectObserver* LLPanelLandInfo::sObserver = NULL; LLPanelLandInfo* LLPanelLandInfo::sInstance = NULL; @@ -224,6 +228,14 @@ void LLPanelLandInfo::refresh() //static void LLPanelLandInfo::onClickClaim() { +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) +/* + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + return; + } +*/ +// [/RLVa:KB] LLViewerParcelMgr::getInstance()->startBuyLand(); } diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index cd1dc0f0701de1e5173fe84d353a9449060df4c8..d0b21a6ac33d668dfe46512d19bf54140ee24a6b 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -56,6 +56,9 @@ #include "lltoggleablemenu.h" #include "llviewermenu.h" #include "llviewerregion.h" +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks"); @@ -771,15 +774,22 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const std::string command_name = userdata.asString(); if("add_landmark" == command_name) { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - if(landmark) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLNotificationsUtil::add("LandmarkAlreadyExists"); - } - else - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + if(landmark) + { + LLNotificationsUtil::add("LandmarkAlreadyExists"); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + } +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 } +// [/RLVa:KB] } else if ("category" == command_name) { @@ -1045,6 +1055,12 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const } return false; } +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + else if("add_landmark" == command_name) + { + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + } +// [/RLVa:KB] else { LL_WARNS() << "Unprocessed command has come: " << command_name << LL_ENDL; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 3665910c633effc7954561d97c5f1e04c3dda797..35c0df81b41cffb353f532b589aa19032123bb4b 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -66,6 +66,10 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" //#include "llfirstuse.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "llvoavatarself.h" +// [/RLVa:KB] #include "lldrawpool.h" @@ -353,6 +357,14 @@ void LLPanelObject::getState( ) BOOL enable_scale = enable_modify; BOOL enable_rotate = enable_move; // already accounts for a case of children, which needs permModify() as well +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == objectp->getRootEdit()) ) + enable_move = enable_scale = enable_rotate = FALSE; + } +// [/RLVa:KB] + LLVector3 vec; if (enable_move) { diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 7756b92a3af1c15a0b5d5e1cef85003799cd1e38..237ed5cf27cac691d07383c07dc9e76cee6e48b9 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -66,6 +66,11 @@ #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llviewermessage.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] const LLColor4U DEFAULT_WHITE(255, 255, 255); @@ -286,8 +291,16 @@ void LLTaskInvFVBridge::openItem() BOOL LLTaskInvFVBridge::isItemRenameable() const { - if(gAgent.isGodlike()) return TRUE; +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if ( (rlv_handler_t::isEnabled()) && (object) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return FALSE; + } +// [/RLVa:KB] + + if(gAgent.isGodlike()) return TRUE; +// LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { LLInventoryItem* item = (LLInventoryItem*)(object->getInventoryObject(mUUID)); @@ -302,7 +315,15 @@ BOOL LLTaskInvFVBridge::isItemRenameable() const BOOL LLTaskInvFVBridge::renameItem(const std::string& new_name) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if ( (rlv_handler_t::isEnabled()) && (object) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return FALSE; + } +// [/RLVa:KB] + +// LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) { LLViewerInventoryItem* item = NULL; @@ -329,12 +350,45 @@ BOOL LLTaskInvFVBridge::isItemMovable() const // return TRUE; //} //return FALSE; +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if (rlv_handler_t::isEnabled()) + { + const LLViewerObject* pObj = gObjectList.findObject(mPanel->getTaskUUID()); + if (pObj) + { + if (gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit())) + { + return FALSE; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObj->getRootEdit()) ) + return FALSE; + } + } + } +// [/RLVa:KB] return TRUE; } BOOL LLTaskInvFVBridge::isItemRemovable() const { const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a + if ( (object) && (rlv_handler_t::isEnabled()) ) + { + if (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) + { + return FALSE; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) ) + return FALSE; + } + } +// [/RLVa:KB] + if(object && (object->permModify() || object->permYouOwner())) { @@ -483,6 +537,13 @@ BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const const LLPermissions& perm = inv->getPermissions(); bool can_copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE); +// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + // Kind of redundant due to the note below, but in case that ever gets fixed + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + return FALSE; + } +// [/RLVa:KB] if (object->isAttachment() && !can_copy) { //RN: no copy contents of attachments cannot be dragged out @@ -544,6 +605,19 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if (canOpenItem()) { items.push_back(std::string("Task Open")); +// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + if (rlv_handler_t::isEnabled()) + { + LLViewerObject* pAttachObj = gObjectList.findObject(mPanel->getTaskUUID()); + bool fLocked = (pAttachObj) ? gRlvAttachmentLocks.isLockedAttachment(pAttachObj->getRootEdit()) : false; + if ( ((LLAssetType::AT_NOTECARD == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (fLocked))) || + ((LLAssetType::AT_LSL_TEXT == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (fLocked))) || + ((LLAssetType::AT_TEXTURE == item->getType()) && (!RlvActions::canPreviewTextures()))) + { + disabled_items.push_back(std::string("Task Open")); + } + } +// [/RLVa:KB] } items.push_back(std::string("Task Properties")); if ((flags & FIRST_SELECTED_ITEM) == 0) @@ -553,7 +627,10 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemRenameable()) { items.push_back(std::string("Task Rename")); - if ((flags & FIRST_SELECTED_ITEM) == 0) +// if ((flags & FIRST_SELECTED_ITEM) == 0) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Added: RLVa-1.2.1f + if ( (!isItemRenameable()) || ((flags & FIRST_SELECTED_ITEM) == 0) ) +// [/RLVa:KB] { disabled_items.push_back(std::string("Task Rename")); } @@ -561,6 +638,12 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemRemovable()) { items.push_back(std::string("Task Remove")); +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Added: RLVa-1.2.1f + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Task Remove")); + } +// [/RLVa:KB] } hide_context_entries(menu, items, disabled_items); @@ -942,6 +1025,13 @@ void LLTaskLSLBridge::openItem() { return; } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT); + return; + } +// [/RLVa:KB] if (object->permModify() || gAgent.isGodlike()) { LLSD floater_key; @@ -1004,6 +1094,14 @@ void LLTaskNotecardBridge::openItem() return; } +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD); + return; + } +// [/RLVa:KB] + // Note: even if we are not allowed to modify copyable notecard, we should be able to view it LLInventoryItem *item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mUUID)); BOOL item_copy = item && gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 1d87aa6f5d5a5ccd82e467a30055725de10515e6..7012458807e9e9df41a6106b61b74ae9fba201ff 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -72,6 +72,9 @@ #include "llwearableitemslist.h" #include "llwearabletype.h" #include "llweb.h" +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) +#include "rlvhandler.h" +// [/RLVa:KB] static LLPanelInjector<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit"); @@ -596,6 +599,10 @@ void LLPanelOutfitEdit::toggleAddWearablesPanel() void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables) { +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + show_add_wearables = (show_add_wearables) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)); +// [/RLVa:KB] + mAddWearablesPanel->setVisible(show_add_wearables); getChild<LLUICtrl>("show_add_wearables_btn")->setValue(show_add_wearables); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 6a0ea04fa6a050d14e95bb9a573c1f674eb5c2d7..827c7c1c227f17f1325cf5eac4a566202cadbb19 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -57,6 +57,12 @@ class LLPanelOutfitsInventory : public LLPanel static LLSidepanelAppearance* getAppearanceSP(); +// [RLVa:KB] - Checked: 2010-08-24 (RLVa-1.4.0a) | Added: RLVa-1.2.1a + LLTabContainer* getAppearanceTabs() { return mAppearanceTabs; } + LLOutfitsList* getMyOutfitsPanel() { return mMyOutfitsPanel; } + LLPanelWearing* getCurrentOutfitPanel() { return mCurrentOutfitPanel; } +// [/RLVa:KB] + static LLPanelOutfitsInventory* findInstance(); protected: diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index be174475e18e4df9f60522763e46a1e0882b0e03..dd3ecc80c90237fc9a6b4cfc30357149e54617e3 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -74,6 +74,10 @@ #include "llagentui.h" #include "llslurl.h" +// [RLVa:KB] - Checked: RLVa-1.2.2 +#include "rlvactions.h" +// [/RLVa:KB] + #define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 @@ -663,6 +667,9 @@ BOOL LLPanelPeople::postBuild() mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); mNearbyList->setShowIcons("NearbyListShowIcons"); mNearbyList->setShowCompleteName(!gSavedSettings.getBOOL("NearbyListHideUsernames")); +// [RLVa:KB] - Checked: RLVa-1.2.0 + mNearbyList->setRlvCheckShowNames(true); +// [/RLVa:KB] mMiniMap = (LLNetMap*)getChildView("Net Map",true); mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); @@ -836,7 +843,18 @@ void LLPanelPeople::updateNearbyList() std::vector<LLVector3d> positions; - LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); +// [RLVa:KB] - Checked: RLVa-2.0.3 + if (RlvActions::canShowNearbyAgents()) + { +// [/RLVa:KB] + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); +// [RLVa:KB] - Checked: RLVa-2.0.3 + } + else + { + mNearbyList->getIDs().clear(); + } +// [/RLVa:KB] mNearbyList->setDirty(); DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); @@ -855,6 +873,9 @@ void LLPanelPeople::updateRecentList() void LLPanelPeople::updateButtons() { std::string cur_tab = getActiveTabName(); +// [RLVa:KB] - Checked: RLVa-1.4.9 + bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME); +// [/RLVa:KB] bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); bool group_tab_active = (cur_tab == GROUP_TAB_NAME); //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); @@ -895,8 +916,12 @@ void LLPanelPeople::updateButtons() LLPanel* cur_panel = mTabContainer->getCurrentPanel(); if (cur_panel) { +// [RLVa:KB] - Checked: RLVa-1.2.0 if (cur_panel->hasChild("add_friend_btn", TRUE)) - cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); + cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self && ((!nearby_tab_active) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, selected_id)))); +// [/RLBa:KB] +// if (cur_panel->hasChild("add_friend_btn", TRUE)) +// cur_panel->getChildView("add_friend_btn")->setEnabled(item_selected && !is_friend && !is_self); if (friends_tab_active) { @@ -909,6 +934,16 @@ void LLPanelPeople::updateButtons() } } } + +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (nearby_tab_active) && (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) ) + { + bool fCanShowNames = true; + std::for_each(selected_uuids.begin(), selected_uuids.end(), [&fCanShowNames](const LLUUID& idAgent) { fCanShowNames &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + if (!fCanShowNames) + item_selected = multiple_selected = false; + } +// [/RLBa:KB] } std::string LLPanelPeople::getActiveTabName() const @@ -1138,6 +1173,13 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) return; } +// [RLVa:KB] - Checked: RLVa-2.0.1 + if ( (RlvActions::isRlvEnabled()) && (NEARBY_TAB_NAME == getActiveTabName()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, clicked_id)) ) + { + return; + } +// [/RLVa:KB] + #if 0 // SJB: Useful for testing, but not currently functional or to spec LLAvatarActions::showProfile(clicked_id); #else // spec says open IM window @@ -1253,6 +1295,15 @@ void LLPanelPeople::onImButtonClicked() { uuid_vec_t selected_uuids; getCurrentItemIDs(selected_uuids); +// [RLVa:KB] - Checked: RLVa-2.0.1 + if ( (RlvActions::isRlvEnabled()) && (NEARBY_TAB_NAME == getActiveTabName()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) ) + { + bool fCanShowNames = true; + std::for_each(selected_uuids.begin(), selected_uuids.end(), [&fCanShowNames](const LLUUID& idAgent) { fCanShowNames &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + if (!fCanShowNames) + return; + } +// [/RLVa:KB] if ( selected_uuids.size() == 1 ) { // if selected only one person then start up IM diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 14205cebe2fd831f3daafcd098bf8fe431bf7622..f76e21ab9ca7319e63f6511cfaf77323a6f93e57 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -57,6 +57,11 @@ class LLPanelPeople // when voice is available /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); +// [RLVa:KB] - Checked: RLVa-1.2.0 + LLAvatarList* getNearbyList() { return mNearbyList; } + void updateNearbyList(); +// [/RLVa:KB] + // internals class Updater; @@ -78,7 +83,7 @@ class LLPanelPeople // methods indirectly called by the updaters void updateFriendListHelpText(); void updateFriendList(); - void updateNearbyList(); +// void updateNearbyList(); void updateRecentList(); bool isItemsFreeOfFriends(const uuid_vec_t& uuids); diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 42cecc9986c7c17f3cc4daef16bfbbd7aa90d72f..f3c693a29aa384ea57444076a9bcd2a3897ce7e5 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -46,6 +46,9 @@ #include "llviewerregion.h" #include "llvoavatarself.h" #include "roles_constants.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +// [/RLVa:KB] namespace LLPanelPeopleMenus { @@ -188,7 +191,10 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) for (;id != uuids_end; ++id) { - if ( LLAvatarActions::isFriend(*id) ) +// if ( LLAvatarActions::isFriend(*id) ) +// [RLVa:KB] - Checked: 2014-03-31 (RLVa-2.0.1) + if ( (LLAvatarActions::isFriend(*id)) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, *id)) ) +// [/RLVa:KB] { result = false; break; @@ -211,7 +217,10 @@ bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata) for (;id != uuids_end; ++id) { - if ( !LLAvatarActions::isFriend(*id) ) +// if ( !LLAvatarActions::isFriend(*id) ) +// [RLVa:KB] - Checked: 2014-03-31 (RLVa-2.0.1) + if ( (!LLAvatarActions::isFriend(*id)) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, *id)) ) +// [/RLVa:KB] { result = false; break; @@ -314,14 +323,29 @@ void PeopleContextMenu::requestTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::teleportRequest(), // so we have to use a wrapper. +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = (!m_fRlvCheck) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mUUIDs.front())); + RlvActions::setShowName(RlvActions::SNC_TELEPORTREQUEST, fRlvCanShowName); LLAvatarActions::teleportRequest(mUUIDs.front()); + RlvActions::setShowName(RlvActions::SNC_TELEPORTREQUEST, true); +// [/RLVa:KB] +// LLAvatarActions::teleportRequest(mUUIDs.front()); } void PeopleContextMenu::offerTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(), // so we have to use a wrapper. +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = true; + if ( (m_fRlvCheck) && (RlvActions::isRlvEnabled()) ) + std::for_each(mUUIDs.begin(), mUUIDs.end(), [&fRlvCanShowName](const LLUUID& idAgent) { fRlvCanShowName &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + + RlvActions::setShowName(RlvActions::SNC_TELEPORTOFFER, fRlvCanShowName); LLAvatarActions::offerTeleport(mUUIDs); + RlvActions::setShowName(RlvActions::SNC_TELEPORTOFFER, true); +// [/RLVa:KB] +// LLAvatarActions::offerTeleport(mUUIDs); } void PeopleContextMenu::eject() @@ -377,7 +401,29 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - if (flags & ITEM_IN_MULTI_SELECTION) +// [RLVa:KB] - Checked: RLVa-1.5.0 + bool fRlvCanShowName = true; + if ( (m_fRlvCheck) && (RlvActions::isRlvEnabled()) ) + std::for_each(mUUIDs.begin(), mUUIDs.end(), [&fRlvCanShowName](const LLUUID& idAgent) { fRlvCanShowName &= RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgent); }); + + if (!fRlvCanShowName) + { + if (flags & ITEM_IN_MULTI_SELECTION) + { + items.push_back(std::string("offer_teleport")); + } + else + { + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("request_teleport")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("zoom_in")); + items.push_back(std::string("block_unblock")); + } + } + else if (flags & ITEM_IN_MULTI_SELECTION) +// [/RLVa:KB] +// if (flags & ITEM_IN_MULTI_SELECTION) { items.push_back(std::string("add_friends")); items.push_back(std::string("remove_friends")); diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index 3bc1f8caf7da486cb889edcc82da13b673ea7919..6091d37257eefb2245e099ea98cd267338b82d09 100644 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -38,6 +38,9 @@ namespace LLPanelPeopleMenus class PeopleContextMenu : public LLListContextMenu { public: +// [RLVa:KB] - Checked: RLVa-1.5.0 + PeopleContextMenu() : m_fRlvCheck(false) {} +// [/RLVa:KB] /*virtual*/ LLContextMenu* createMenu(); protected: @@ -51,6 +54,11 @@ class PeopleContextMenu : public LLListContextMenu void eject(); void startConference(); void requestTeleport(); + +// [RLVa:KB] - Checked: RLVa-1.5.0 +protected: + bool m_fRlvCheck; +// [/RLVa:KB] }; /** @@ -58,6 +66,10 @@ class PeopleContextMenu : public LLListContextMenu */ class NearbyPeopleContextMenu : public PeopleContextMenu { +// [RLVa:KB] - Checked: RLVa-1.5.0 +public: + NearbyPeopleContextMenu() : PeopleContextMenu() { m_fRlvCheck = true; } +// [/RLVa:KB] protected: /*virtual*/ void buildContextMenu(class LLMenuGL& menu, U32 flags); }; diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index ef16427713692b7b9188ee91436405b14ff87260..1680326d9e54a6b12b64be7da09f58c24e22b4a3 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -70,6 +70,11 @@ #include "llavatarnamecache.h" #include "llcachename.h" +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) +#include "llslurl.h" +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] U8 string_value_to_click_action(std::string p_value); std::string click_action_to_string_value( U8 action); @@ -388,62 +393,78 @@ void LLPanelPermissions::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); std::string creator_app_link; - LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_app_link); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + const bool creators_identical = LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_app_link); + std::string owner_app_link; + const bool owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_app_link); +// [/RLVa:KB] +// LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_app_link); // Style for creator and owner links (both group and agent) - LLStyle::Params style_params; - LLColor4 link_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.color = link_color; - style_params.readonly_color = link_color; - style_params.is_link = true; // link will be added later - const LLFontGL* fontp = mLabelCreatorName->getFont(); - style_params.font.name = LLFontGL::nameFromFont(fontp); - style_params.font.size = LLFontGL::sizeFromFont(fontp); - style_params.font.style = "UNDERLINE"; + //LLStyle::Params style_params; + //LLColor4 link_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + //style_params.color = link_color; + //style_params.readonly_color = link_color; + //style_params.is_link = true; // link will be added later + //const LLFontGL* fontp = mLabelCreatorName->getFont(); + //style_params.font.name = LLFontGL::nameFromFont(fontp); + //style_params.font.size = LLFontGL::sizeFromFont(fontp); + //style_params.font.style = "UNDERLINE"; LLAvatarName av_name; - style_params.link_href = creator_app_link; - if (LLAvatarNameCache::get(mCreatorID, &av_name)) - { - updateCreatorName(mCreatorID, av_name, style_params); - } - else - { - if (mCreatorCacheConnection.connected()) - { - mCreatorCacheConnection.disconnect(); - } - mLabelCreatorName->setText(LLTrans::getString("None")); - mCreatorCacheConnection = LLAvatarNameCache::get(mCreatorID, boost::bind(&LLPanelPermissions::updateCreatorName, this, _1, _2, style_params)); - } - getChild<LLAvatarIconCtrl>("Creator Icon")->setValue(mCreatorID); - getChild<LLAvatarIconCtrl>("Creator Icon")->setVisible(TRUE); + //style_params.link_href = creator_app_link; +// [RLVa:KB] - Checked: RLVa-2.0.1 + // Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie + if ( (RlvActions::isRlvEnabled()) && (creators_identical) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, mCreatorID)) && ( (mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + { + creator_app_link = LLSLURL("agent", mCreatorID, "rlvanonym").getSLURLString(); + } + mLabelCreatorName->setText(creator_app_link); +// [/RLVa:KB] +// if (LLAvatarNameCache::get(mCreatorID, &av_name)) +// { +// updateCreatorName(mCreatorID, av_name, style_params); +// } +// else +// { +// if (mCreatorCacheConnection.connected()) +// { +// mCreatorCacheConnection.disconnect(); +// } +// mLabelCreatorName->setText(LLTrans::getString("None")); +// mCreatorCacheConnection = LLAvatarNameCache::get(mCreatorID, boost::bind(&LLPanelPermissions::updateCreatorName, this, _1, _2, style_params)); +// } +// getChild<LLAvatarIconCtrl>("Creator Icon")->setValue(mCreatorID); +// getChild<LLAvatarIconCtrl>("Creator Icon")->setVisible(TRUE); mLabelCreatorName->setEnabled(TRUE); // Update owner text field getChildView("Owner:")->setEnabled(TRUE); - std::string owner_app_link; - const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_app_link); +// std::string owner_app_link; +// const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_app_link); if (LLSelectMgr::getInstance()->selectIsGroupOwned()) { // Group owned already displayed by selectGetOwner - LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mOwnerID); - if (group_data && group_data->isGroupPropertiesDataComplete()) - { - style_params.link_href = owner_app_link; - mLabelOwnerName->setText(group_data->mName, style_params); - getChild<LLGroupIconCtrl>("Owner Group Icon")->setIconId(group_data->mInsigniaID); - getChild<LLGroupIconCtrl>("Owner Group Icon")->setVisible(TRUE); - getChild<LLUICtrl>("Owner Icon")->setVisible(FALSE); - } - else - { - // Triggers refresh - LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mOwnerID); - } +// [RLVa:KB] - Checked: RLVa-2.0.1 + childSetValue("Owner Name", owner_app_link); +// [/RLVa:KB] +// LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mOwnerID); +// if (group_data && group_data->isGroupPropertiesDataComplete()) +// { +// style_params.link_href = owner_app_link; +// mLabelOwnerName->setText(group_data->mName, style_params); +// getChild<LLGroupIconCtrl>("Owner Group Icon")->setIconId(group_data->mInsigniaID); +// getChild<LLGroupIconCtrl>("Owner Group Icon")->setVisible(TRUE); +// getChild<LLUICtrl>("Owner Icon")->setVisible(FALSE); +// } +// else +// { +// // Triggers refresh +// LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mOwnerID); +// } } else { @@ -464,24 +485,31 @@ void LLPanelPermissions::refresh() owner_id = mLastOwnerID; } - style_params.link_href = owner_app_link; - if (LLAvatarNameCache::get(owner_id, &av_name)) - { - updateOwnerName(owner_id, av_name, style_params); - } - else +// style_params.link_href = owner_app_link; +// [RLVa:KB] - Checked: RLVa-2.0.1 + if ( (RlvActions::isRlvEnabled()) && (owners_identical) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, mOwnerID)) ) { - if (mOwnerCacheConnection.connected()) - { - mOwnerCacheConnection.disconnect(); - } - mLabelOwnerName->setText(LLTrans::getString("None")); - mOwnerCacheConnection = LLAvatarNameCache::get(owner_id, boost::bind(&LLPanelPermissions::updateOwnerName, this, _1, _2, style_params)); + owner_app_link = LLSLURL("agent", mOwnerID, "rlvanonym").getSLURLString(); } - - getChild<LLAvatarIconCtrl>("Owner Icon")->setValue(owner_id); - getChild<LLAvatarIconCtrl>("Owner Icon")->setVisible(TRUE); - getChild<LLUICtrl>("Owner Group Icon")->setVisible(FALSE); + mLabelOwnerName->setText(owner_app_link); +// [/RLVa:KB] +// if (LLAvatarNameCache::get(owner_id, &av_name)) +// { +// updateOwnerName(owner_id, av_name, style_params); +// } +// else +// { +// if (mOwnerCacheConnection.connected()) +// { +// mOwnerCacheConnection.disconnect(); +// } +// mLabelOwnerName->setText(LLTrans::getString("None")); +// mOwnerCacheConnection = LLAvatarNameCache::get(owner_id, boost::bind(&LLPanelPermissions::updateOwnerName, this, _1, _2, style_params)); +// } +// +// getChild<LLAvatarIconCtrl>("Owner Icon")->setValue(owner_id); +// getChild<LLAvatarIconCtrl>("Owner Icon")->setVisible(TRUE); +// getChild<LLUICtrl>("Owner Group Icon")->setVisible(FALSE); } mLabelOwnerName->setEnabled(TRUE); diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 104316e2534bcf5d08e67534843f5bfaa1a800b4..c25c5d8b90290d2e08ebeaa756e9141a7b69eb17 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -52,6 +52,9 @@ #include "llviewercontrol.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" +// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] const F64 COVENANT_REFRESH_TIME_SEC = 60.0f; @@ -611,7 +614,10 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, mLastSelectedRegionID = region->getRegionID(); LLPanelPlaceInfo::processParcelInfo(parcel_data); - mYouAreHerePanel->setVisible(is_current_parcel); +// mYouAreHerePanel->setVisible(is_current_parcel); +// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.4.5) | Added: RLVa-1.2.1 + mYouAreHerePanel->setVisible(is_current_parcel && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))); +// [/RLVa:KB] getChild<LLAccordionCtrlTab>("sales_tab")->setVisible(for_sale); mAccordionCtrl->arrange(); } @@ -679,6 +685,9 @@ void LLPanelPlaceProfile::updateYouAreHereBanner(void* userdata) BOOL display_banner = gAgent.getRegion()->getRegionID() == self->mLastSelectedRegionID && LLAgentUI::checkAgentDistance(self->mPosRegion, radius); - self->mYouAreHerePanel->setVisible(display_banner); +// self->mYouAreHerePanel->setVisible(display_banner); +// [RLVa:KB] - Checked: 2010-09-02 (RLVa-1.4.5) | Added: RLVa-1.2.1 + self->mYouAreHerePanel->setVisible(display_banner && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))); +// [/RLVa:KB] } } diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index d97f60ed229ab16320932951e9a13c896e9b7177..63690c0e533b961dcbea164b4130a660b4065944 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -52,13 +52,17 @@ class LLPanelProfile : public LLPanel S32 notifyParent(const LLSD& info); +// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RVLa-1.2.0f + const LLUUID& getAvatarId() const { return mAvatarId; } +// [/RLVa:KB] + protected: LLPanelProfile(); virtual void onTabSelected(const LLSD& param); - const LLUUID& getAvatarId() { return mAvatarId; } +// const LLUUID& getAvatarId() { return mAvatarId; } void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp index 109013498ee71b17d8a4510383003113ae365939..b0dafe5a1195a396592fcb24bcfbeea7530f414f 100644 --- a/indra/newview/llpaneltopinfobar.cpp +++ b/indra/newview/llpaneltopinfobar.cpp @@ -44,6 +44,9 @@ #include "llviewermenu.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 +#include "rlvhandler.h" +// [/RLVa:KB] class LLPanelTopInfoBar::LLParcelChangeObserver : public LLParcelObserver { @@ -452,28 +455,47 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item) { if (item == "landmark") { - LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); - - if(landmark == NULL) - { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); - } - else +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); +// [/RLVa:KB] + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + + if(landmark == NULL) + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); + } +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 } +// [/RLVa:KB] } else if (item == "copy") { - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl, false); - LLUIString location_str(slurl.getSLURLString()); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { +// [/RLVa:KB] + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl, false); + LLUIString location_str(slurl.getSLURLString()); - LLClipboard::instance().copyToClipboard(location_str,0,location_str.length()); + LLClipboard::instance().copyToClipboard(location_str,0,location_str.length()); +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + } +// [/RLVa:KB] } } void LLPanelTopInfoBar::onInfoButtonClicked() { +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); } diff --git a/indra/newview/llpaneltopinfobar.h b/indra/newview/llpaneltopinfobar.h index 78dd99702906f95f2f32bc6aa0045d838ceb6dbb..5405548ea8b4bbfcbbf427c735e73d01544874c9 100644 --- a/indra/newview/llpaneltopinfobar.h +++ b/indra/newview/llpaneltopinfobar.h @@ -61,6 +61,12 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>, boost::signals2::connection setResizeCallback( const resize_signal_t::slot_type& cb ); +// [RLVa:KB] - Checked: 2014-03-23 (RLVa-1.4.10) + /** + * Shorthand to call updateParcelInfoText() and updateParcelIcons(). + */ + void update(); +// [/RLV:KB] private: class LLParcelChangeObserver; @@ -110,10 +116,10 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>, */ void onNavBarShowParcelPropertiesCtrlChanged(); - /** - * Shorthand to call updateParcelInfoText() and updateParcelIcons(). - */ - void update(); +// /** +// * Shorthand to call updateParcelInfoText() and updateParcelIcons(). +// */ +// void update(); /** * Updates parcel info text (mParcelInfoText). diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 89cb495db94023bf67573e99788814c0a772f0a8..7b750fe1d5a0c93be7cda1e818523b7242a2d8b9 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -46,6 +46,10 @@ #include "llwearableitemslist.h" #include "llsdserialize.h" #include "llclipboard.h" +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) +#include "rlvcommon.h" +#include "rlvhandler.h" +// [/RLVa:KB] // Context menu and Gear menu helper. static void edit_outfit() @@ -110,6 +114,9 @@ class LLWearingContextMenu : public LLListContextMenu bool bp_selected = false; // true if body parts selected bool clothes_selected = false; bool attachments_selected = false; +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + S32 rlv_locked_count = 0; +// [/RLVa:KB] // See what types of wearables are selected. for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it) @@ -135,14 +142,27 @@ class LLWearingContextMenu : public LLListContextMenu { attachments_selected = true; } +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(*it)) ) + { + rlv_locked_count++; + } +// [/RLVa:KB] } // Enable/disable some menu items depending on the selection. +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + bool rlv_blocked = (mUUIDs.size() == rlv_locked_count); +// [/RLVa:KB] bool allow_detach = !bp_selected && !clothes_selected && attachments_selected; bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected; menu->setItemVisible("take_off", allow_take_off); menu->setItemVisible("detach", allow_detach); +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + menu->setItemEnabled("take_off", !rlv_blocked); + menu->setItemEnabled("detach", !rlv_blocked); +// [/RLVa:KB] menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach); menu->setItemVisible("show_original", mUUIDs.size() == 1); menu->setItemVisible("edit_item", FALSE); diff --git a/indra/newview/llparcelselection.h b/indra/newview/llparcelselection.h index 06d9141efb1b08bf35996d7e0643293b25d060ff..dcd23f4b3d72b98c7f84a5ec098a4bf3fbcab14b 100644 --- a/indra/newview/llparcelselection.h +++ b/indra/newview/llparcelselection.h @@ -46,7 +46,10 @@ class LLParcelSelection : public LLRefCount // this can return NULL at any time, as parcel selection // might have been invalidated. - LLParcel* getParcel() { return mParcel; } +// [RLVa:KB] - Checked: 2012-02-09 (RLVa-1.4.5) | Modified: RLVa-1.4.5 + LLParcel* getParcel() const { return mParcel; } +// [/RLVa:KB] +// LLParcel* getParcel() { return mParcel; } // Return the number of grid units that are owned by you within // the selection (computed by server). diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index d177384b5ac8c602b19d64e0b0c919d06aabac0f..90b448d7ac25ca6ed00eebfd078bc62e89ac046a 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -87,6 +87,10 @@ #include "llexperiencecache.h" #include "llfloaterexperienceprofile.h" #include "llviewerassetupload.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] const std::string HELLO_LSL = "default\n" @@ -2055,6 +2059,14 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) //self->mRunningCheckbox->get(); if( object ) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedGeneric(); + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); msg->nextBlockFast(_PREHASH_AgentData); @@ -2080,6 +2092,14 @@ void LLLiveLSLEditor::onReset(void *userdata) LLViewerObject* object = gObjectList.findObject( self->mObjectUUID ); if(object) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedGeneric(); + return; + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ScriptReset); msg->nextBlockFast(_PREHASH_AgentData); @@ -2206,6 +2226,14 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) return; } +// [RLVa:KB] - Checked: 2010-11-25 (RLVa-1.2.2b) | Modified: RLVa-1.2.2b + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) ) + { + RlvUtil::notifyBlockedGeneric(); + return; + } +// [/RLVa:KB] + // get the latest info about it. We used to be losing the script // name on save, because the viewer object version of the item, // and the editor version would get out of synch. Here's a good diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 681787bcbe937fb660b354fd8a943221ca76ccc9..852766b0cde883a115638edbea1c9f5f7c3620a2 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -1128,8 +1128,17 @@ LLToast* LLScreenChannel::getToastByNotificationID(LLUUID id) std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id); +// if (it == mStoredToastList.end()) +// return NULL; +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Modified: Catznip-2.5.0a if (it == mStoredToastList.end()) - return NULL; + { + // If we can't find it among the stored toasts then widen it to "all visible toasts" + it = find(mToastList.begin(), mToastList.end(), id); + if (it == mToastList.end()) + return NULL; + } +// [/SL:KB] return it->getToast(); } diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h index 51f57afdc91a2f94a0df3dea63d09f6a51ccb3e6..9318cbb1d66e706a70913204d9eecbd8d5971d51 100644 --- a/indra/newview/llscriptruntimeperms.h +++ b/indra/newview/llscriptruntimeperms.h @@ -39,7 +39,14 @@ typedef struct _script_perm { const U32 NUM_SCRIPT_PERMISSIONS = 16; const S32 SCRIPT_PERMISSION_DEBIT = 0; +// [RLVa:KB] - Checked: RLVa-2.0.0 +const S32 SCRIPT_PERMISSION_TAKE_CONTROLS = 1; +// [/RLVa:KB] const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3; +// [RLVa:KB] - Checked: RLVa-2.0.0 +const S32 SCRIPT_PERMISSION_ATTACH = 4; +const S32 SCRIPT_PERMISSION_TELEPORT = 11; +// [/RLVa:KB] const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14; static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{ diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index aee6bcb05e20f16ddb5b3f9b03dd8d69b0431d25..f93a81fb56934007dd1816d649b96f5041213690 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -95,6 +95,11 @@ #include "pipeline.h" #include "llviewershadermgr.h" #include "llpanelface.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvmodifiers.h" +// [/RLVa:KB] #include "llglheaders.h" #include "llinventoryobserver.h" @@ -726,6 +731,16 @@ bool LLSelectMgr::enableLinkObjects() { new_value = false; } +// [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g + if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp); + if (hSel->getFirstRootNode(&f, TRUE) != NULL) + new_value = false; + } +// [/RLVa:KB] return new_value; } @@ -738,7 +753,16 @@ bool LLSelectMgr::enableUnlinkObjects() first_editable_object && !first_editable_object->isAttachment() && !first_editable_object->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()); - +// [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g + if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp); + if (hSel->getFirstRootNode(&f, TRUE) != NULL) + new_value = false; + } +// [/RLVa:KB] return new_value; } @@ -2554,7 +2578,7 @@ void LLSelectMgr::logNoOp(LLSelectNode* node, void *) // static void LLSelectMgr::logAttachmentRequest(LLSelectNode* node, void *) { - LLAttachmentsMgr::instance().onAttachmentRequested(node->mItemID); +// LLAttachmentsMgr::instance().onAttachmentRequested(node->mItemID); } // static @@ -3582,6 +3606,16 @@ BOOL LLSelectMgr::selectGetPermissions(LLPermissions& result_perm) void LLSelectMgr::selectDelete() { +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) + { + make_ui_sound("UISndInvalidOp"); + if (!gFloaterTools->getVisible()) + deselectAll(); + return; + } +// [/RLVa:KB] + S32 deleteable_count = 0; BOOL locked_but_deleteable_object = FALSE; @@ -3764,6 +3798,15 @@ BOOL LLSelectMgr::selectGetEditMoveLinksetPermissions(bool &move, bool &modify) (object->permModify() || selecting_linked_set)) { this_object_movable = true; + +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g + if ( (rlv_handler_t::isEnabled()) && + ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) ) + { + if ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit())) + this_object_movable = false; + } +// [/RLVa:KB] } move = move && this_object_movable; modify = modify && object->permModify(); @@ -3935,7 +3978,10 @@ struct LLDuplicateData void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy) { - if (mSelectedObjects->isAttachment()) +// if (mSelectedObjects->isAttachment()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + if ( (mSelectedObjects->isAttachment()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { //RN: do not duplicate attachments make_ui_sound("UISndInvalidOp"); @@ -4403,11 +4449,36 @@ void LLSelectMgr::convertTransient() void LLSelectMgr::deselectAllIfTooFar() { +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (!mSelectedObjects->isEmpty()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_EDITOBJ))) ) + { + struct NotTransientOrFocusedMediaOrEditable : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* pNode) + { + const LLViewerObject* pObj = pNode->getObject(); + return (!pNode->isTransient()) && (pObj) && (!RlvActions::canEdit(pObj)) && (pObj->getID() != LLViewerMediaFocus::getInstance()->getFocusedObjectID()); + } + } f; + if (mSelectedObjects->getFirstRootNode(&f, TRUE)) + deselectAll(); + } +// [/RLVa:KB] + if (mSelectedObjects->isEmpty() || mSelectedObjects->mSelectType == SELECT_TYPE_HUD) { return; } +// [RLVa:KB] - Checked: RLVa-1.2.0 + // [Fall-back code] Don't allow an active selection (except for HUD attachments - see above) when @interact restricted + if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) + { + deselectAll(); + return; + } +// [/RLVa:KB] + // HACK: Don't deselect when we're navigating to rate an object's // owner or creator. JC if (gMenuObject->getVisible()) @@ -4416,13 +4487,22 @@ void LLSelectMgr::deselectAllIfTooFar() } LLVector3d selectionCenter = getSelectionCenterGlobal(); - if (gSavedSettings.getBOOL("LimitSelectDistance") +// if (gSavedSettings.getBOOL("LimitSelectDistance") +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + + BOOL fRlvFartouch = gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH) && LLToolMgr::instance().inEdit(); + if ( (gSavedSettings.getBOOL("LimitSelectDistance") || (fRlvFartouch) ) +// [/RLVa:KB] && (!mSelectedObjects->getPrimaryObject() || !mSelectedObjects->getPrimaryObject()->isAvatar()) && (mSelectedObjects->getPrimaryObject() != LLViewerMediaFocus::getInstance()->getFocusedObject()) && !mSelectedObjects->isAttachment() && !selectionCenter.isExactlyZero()) { - F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance"); +// F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance"); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f + F32 deselect_dist = (!fRlvFartouch) ? gSavedSettings.getF32("MaxSelectDistance") : s_nFartouchDist; +// [/RLVa:KB] F32 deselect_dist_sq = deselect_dist * deselect_dist; LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter; @@ -7003,7 +7083,10 @@ BOOL LLSelectMgr::canDoDelete() const can_delete = true; } } - +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + can_delete &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()); +// [/RLVa:KB] + return can_delete; } @@ -7035,7 +7118,12 @@ void LLSelectMgr::deselect() //----------------------------------------------------------------------------- BOOL LLSelectMgr::canDuplicate() const { - return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG +// return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + return + (const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL) && + ( (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()) ); +// [/RLVa:KB] } //----------------------------------------------------------------------------- // duplicate() diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 6e2b4a00fc036f299d15db7b5c7f76989d1fee0e..b24330fa762bcebce4d5aeb7226522227fde7308 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -539,3 +539,15 @@ void LLSidepanelAppearance::updateScrollingPanelList() mEditWearable->updateScrollingPanelList(); } } + +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a +bool LLSidepanelAppearance::isOutfitEditPanelVisible() const +{ + return (mOutfitEdit) && (mOutfitEdit->getVisible()); +} + +bool LLSidepanelAppearance::isWearableEditPanelVisible() const +{ + return (mEditWearable) && (mEditWearable->getVisible()); +} +// [/RLVa:KB] diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 7817fd317c07000e9fa244a763cdffbcfedf5a5e..93f23a29f330ad5265e9c709e2eca876d45bccda 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -65,6 +65,14 @@ class LLSidepanelAppearance : public LLPanel void updateToVisibility( const LLSD& new_visibility ); LLPanelEditWearable* getWearable(){ return mEditWearable; } +// [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + bool isOutfitEditPanelVisible() const; + bool isWearableEditPanelVisible() const; + + LLPanelOutfitEdit* getOutfitEditPanel() { return mOutfitEdit; } + LLPanelEditWearable* getWearableEditPanel() { return mEditWearable; } +// [/RLVa:KB] + private: void onFilterEdit(const std::string& search_string); void onVisibilityChanged ( const LLSD& new_visibility ); diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index d508621b41ff29e23bc6aaaf973e29416b4f556f..2522f94a794a26a1b82c0effd77e1313c6f322d9 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -47,7 +47,10 @@ #include "llexperiencecache.h" #include "lltrans.h" #include "llviewerregion.h" - +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] class PropertiesChangedCallback : public LLInventoryCallback { @@ -396,9 +399,20 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) if (item->getCreatorUUID().notNull()) { LLUUID creator_id = item->getCreatorUUID(); - std::string name = - LLSLURL("agent", creator_id, "completename").getSLURLString(); - getChildView("BtnCreator")->setEnabled(TRUE); +// std::string name = +// LLSLURL("agent", creator_id, "completename").getSLURLString(); +// getChildView("BtnCreator")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + // If the object creator matches the object owner we need to anonymize the creator field as well + bool fRlvCanShowCreator = true; + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, creator_id)) && + ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == creator_id) ) || (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) ) + { + fRlvCanShowCreator = false; + } + std::string name = LLSLURL("agent", creator_id, (fRlvCanShowCreator) ? "completename" : "rlvanonym").getSLURLString(); + getChildView("BtnCreator")->setEnabled(fRlvCanShowCreator); +// [/RLVa:KB] getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(FALSE); getChild<LLUICtrl>("LabelCreatorName")->setValue(name); @@ -416,6 +430,9 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) //////////////// if(perm.isOwned()) { +// [RLVa:KB] - Checked: RVLa-2.0.1 + bool fRlvCanShowOwner = true; +// [/RLVa:KB] std::string name; if (perm.isGroupOwned()) { @@ -424,9 +441,16 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) else { LLUUID owner_id = perm.getOwner(); - name = LLSLURL("agent", owner_id, "completename").getSLURLString(); +// name = LLSLURL("agent", owner_id, "completename").getSLURLString(); +// [RLVa:KB] - Checked: RLVa-2.0.1 + fRlvCanShowOwner = RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id); + name = LLSLURL("agent", owner_id, (fRlvCanShowOwner) ? "completename" : "rlvanonym").getSLURLString(); +// [/RLVa:KB] } - getChildView("BtnOwner")->setEnabled(TRUE); +// getChildView("BtnOwner")->setEnabled(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.1 + getChildView("BtnOwner")->setEnabled(fRlvCanShowOwner); +// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(FALSE); getChild<LLUICtrl>("LabelOwnerName")->setValue(name); @@ -787,6 +811,17 @@ void LLSidepanelItemInfo::onClickCreator() if(!item) return; if(!item->getCreatorUUID().isNull()) { +// [RLVa:KB] - Checked: RLVa-1.2.1 + const LLUUID& idCreator = item->getCreatorUUID(); + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idCreator)) ) + { + const LLPermissions& perm = item->getPermissions(); + if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == idCreator) ) || (RlvUtil::isNearbyAgent(idCreator)) ) + { + return; + } + } +// [/RLVa:KB] LLAvatarActions::showProfile(item->getCreatorUUID()); } } @@ -802,6 +837,10 @@ void LLSidepanelItemInfo::onClickOwner() } else { +// [RLVa:KB] - Checked: RLVa-1.0.0 + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, item->getPermissions().getOwner())) ) + return; +// [/RLVa:KB] LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 7fa06f51e30e51d5a84e23e6cb26d189390c2fcb..a6000e6844fdc5c8e5ebe787977a372a64eab11c 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -64,6 +64,10 @@ #include "lltextbase.h" #include "llstring.h" #include "lltrans.h" +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) +#include "llslurl.h" +#include "rlvhandler.h" +// [/RLVa:KB] ///---------------------------------------------------------------------------- /// Class llsidepaneltaskinfo @@ -356,21 +360,28 @@ void LLSidepanelTaskInfo::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + BOOL creators_identical = FALSE; +// [/RLVa:KB] std::string creator_name; LLUUID creator_id; - LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); - - if(creator_id != mCreatorID ) - { - mDACreatorName->setValue(creator_name); - mCreatorID = creator_id; - } - if(mDACreatorName->getValue().asString() == LLStringUtil::null) - { - mDACreatorName->setValue(creator_name); - } - mDACreatorName->setEnabled(TRUE); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + creators_identical = LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); +// [/RLVa:KB] +// LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_name); + +// if(creator_id != mCreatorID ) +// { +// mDACreatorName->setValue(creator_name); +// mCreatorID = creator_id; +// } +// if(mDACreatorName->getValue().asString() == LLStringUtil::null) +// { +// mDACreatorName->setValue(creator_name); +// } +// mDACreatorName->setEnabled(TRUE); +// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row // Update owner text field getChildView("Owner:")->setEnabled(TRUE); @@ -400,17 +411,41 @@ void LLSidepanelTaskInfo::refresh() } } - if(owner_id.isNull() || (owner_id != mOwnerID)) +// if(owner_id.isNull() || (owner_id != mOwnerID)) +// { +// mDAOwnerName->setValue(owner_name); +// mOwnerID = owner_id; +// } +// if(mDAOwnerName->getValue().asString() == LLStringUtil::null) +// { +// mDAOwnerName->setValue(owner_name); +// } +// getChildView("Owner Name")->setEnabled(TRUE); + +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) { - mDAOwnerName->setValue(owner_name); - mOwnerID = owner_id; + // Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie + if ( (creators_identical) && (mCreatorID != gAgent.getID()) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + creator_name = LLSLURL("agent", mCreatorID, "rlvanonym").getSLURLString(); + + // Only anonymize the owner name if all of the selection is owned by the same avie and isn't group owned + if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) && (mOwnerID != gAgent.getID()) ) + owner_name = LLSLURL("agent", mOwnerID, "rlvanonym").getSLURLString(); } - if(mDAOwnerName->getValue().asString() == LLStringUtil::null) + + if(mDACreatorName->getValue().asString() == LLStringUtil::null) { - mDAOwnerName->setValue(owner_name); + mDACreatorName->setValue(creator_name); } + mDACreatorName->setEnabled(TRUE); - getChildView("Owner Name")->setEnabled(TRUE); + if(mDAOwnerName->getValue().asString() == LLStringUtil::null) + { + mDAOwnerName->setValue(owner_name); + } + mDAOwnerName->setEnabled(TRUE); +// [/RLVa:KB] // update group text field getChildView("Group:")->setEnabled(TRUE); diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index a8e012bfa1881eafb5eb7b8391bf1c97d7096348..c7caa8f0433e33c626cb1f16a7590e1239f92ddb 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -34,6 +34,9 @@ #include "llviewernetwork.h" #include "llfiltersd2xmlrpc.h" #include "curl/curl.h" +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) +#include "rlvhandler.h" +// [/RLVa:KB] const char* LLSLURL::SLURL_HTTP_SCHEME = "http"; const char* LLSLURL::SLURL_HTTPS_SCHEME = "https"; const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife"; @@ -389,8 +392,13 @@ std::string LLSLURL::getSLURLString() const S32 x = ll_round( (F32)mPosition[VX] ); S32 y = ll_round( (F32)mPosition[VY] ); S32 z = ll_round( (F32)mPosition[VZ] ); - return LLGridManager::getInstance()->getSLURLBase(mGrid) + - LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); +// return LLGridManager::getInstance()->getSLURLBase(mGrid) + +// LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + return LLGridManager::getInstance()->getSLURLBase(mGrid) + + ( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion))) + ? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RLV_STRING_HIDDEN_REGION) ); +// [/RLVa:KB] } case APP: { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 684d3bd4218f5ccf70ea163d31a7450b740e9f3a..19172bf860ad147072ae84df728bd5ffa5364fef 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -191,6 +191,9 @@ #include "llavatariconctrl.h" #include "llvoicechannel.h" #include "llpathfindingmanager.h" +// [RLVa:KB] - Checked: RLVa-1.2.0 +#include "rlvhandler.h" +// [/RLVa:KB] #include "lllogin.h" #include "llevents.h" @@ -716,6 +719,13 @@ bool idle_startup() show_connect_box = TRUE; } +// [RLVa:KB] - Patch: RLVa-2.1.0 + if (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) + { + show_connect_box = TRUE; + } +// [/RVA:KB] + //setup map of datetime strings to codes and slt & local time offset from utc // *TODO: Does this need to be here? LLStringOps::setupDatetimeInfo(false); @@ -860,6 +870,13 @@ bool idle_startup() return FALSE; } +// [RLVa:KB] - Checked: RLVa-0.2.1 + if (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) + { + RlvHandler::setEnabled(true); + } +// [/RLVa:KB] + // reset the values that could have come in from a slurl // DEV-42215: Make sure they're not empty -- gUserCredential // might already have been set from gSavedSettings, and it's too bad @@ -994,6 +1011,14 @@ bool idle_startup() // their last location, or some URL "-url //sim/x/y[/z]" // All accounts have both a home and a last location, and we don't support // more locations than that. Choose the appropriate one. JC +// [RLVa:KB] - Checked: RLVa-0.2.1 + if ( (RlvHandler::isEnabled()) && (RlvSettings::getLoginLastLocation()) ) + { + // Force login at the last location + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST)); + } +// [/RLVa:KB] + switch (LLStartUp::getStartSLURL().getType()) { case LLSLURL::LOCATION: @@ -1842,6 +1867,14 @@ bool idle_startup() LL_INFOS() << "Creating Inventory Views" << LL_ENDL; LLFloaterReg::getInstance("inventory"); display_startup(); + +// [RLVa:KB] - Checked: RLVa-1.1.0 + if (RlvHandler::isEnabled()) + { + // Regularly process a select subset of retained commands during logon + gIdleCallbacks.addFunction(RlvHandler::onIdleStartup, new LLTimer()); + } +// [/RLVa:KB] LLStartUp::setStartupState( STATE_MISC ); display_startup(); return FALSE; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index b8c227334da1ab21818d0fde9477abf3ead9c359..d777d6a49678c3e5db0cd9150ede98e0efe3ac10 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -87,7 +87,6 @@ // system includes #include <iomanip> - // // Globals // diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp index 3c3c1c96ef99a7c285101803a77820cb66280ad8..ac7ee401bad3c9ad08b5c3d6d16ac4b3b6aec613 100644 --- a/indra/newview/llteleporthistory.cpp +++ b/indra/newview/llteleporthistory.cpp @@ -39,6 +39,9 @@ #include "llviewerregion.h" #include "llworldmap.h" #include "llagentui.h" +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) +#include "rlvhandler.h" +// [/RLVa:KB] ////////////////////////////////////////////////////////////////////////////// // LLTeleportHistoryItem @@ -151,8 +154,16 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) mItems.erase (mItems.begin() + mCurrentItem + 1, mItems.end()); // Append an empty item to the history and make it current. - mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); - mCurrentItem++; +// mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); +// mCurrentItem++; +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + // Only append a new item if the list is currently empty or if not @showloc=n restricted and the last entry wasn't zero'ed out + if ( (mItems.size() == 0) || ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!mItems.back().mGlobalPos.isExactlyZero())) ) + { + mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); + mCurrentItem++; + } +// [RLVa:KB] } // Update current history item. @@ -162,11 +173,23 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) llassert(!"Invalid current teleport history item"); return; } - LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); - mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local); - mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local); - mItems[mCurrentItem].mGlobalPos = new_pos; - mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID(); + +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { +// [/RLVa:KB] + LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); + mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local); + mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local); + mItems[mCurrentItem].mGlobalPos = new_pos; + mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID(); +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + } + else + { + mItems[mCurrentItem] = LLTeleportHistoryItem(RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL), LLVector3d::zero); + } +// [/RLVa:KB] } dump(); diff --git a/indra/newview/llteleporthistory.h b/indra/newview/llteleporthistory.h index db0ccdda59cec04280062ed2f148131c152df4c6..66875279100ce94da15b5b3661f3d84575c6c41a 100644 --- a/indra/newview/llteleporthistory.h +++ b/indra/newview/llteleporthistory.h @@ -233,6 +233,10 @@ class LLTeleportHistory: public LLSingleton<LLTeleportHistory> * Using this connection we get notified when a teleport fails. */ boost::signals2::connection mTeleportFailedConn; + +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + friend class RlvUIEnabler; +// [/RLVa:KB] }; #endif diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index 8a5704939a134f54c3ffda1aa2408f571a72c48f..3025ea57c6a56e57cd10719e01528ed3434aa613 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -33,6 +33,9 @@ #include "lldir.h" #include "llteleporthistory.h" #include "llagent.h" +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) +#include "rlvactions.h" +// [/RLVa:KB] // Max offset for two global positions to consider them as equal const F64 MAX_GLOBAL_POS_OFFSET = 5.0f; @@ -92,6 +95,13 @@ void LLTeleportHistoryStorage::onTeleportHistoryChange() } const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()]; +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + // Make sure we don't attempt to save zero'ed out teleport history items + if (item.mGlobalPos.isExactlyZero()) + { + return; + } +// [/RLVa:KB] addItem(item.mTitle, item.mGlobalPos); save(); @@ -116,6 +126,13 @@ bool LLTeleportHistoryStorage::compareByTitleAndGlobalPos(const LLTeleportHistor void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date) { +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + if (!RlvActions::canShowLocation()) + { + return; + } +// [/RLVa:KB] + LLTeleportHistoryPersistentItem item(title, global_pos, date); slurl_list_t::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), diff --git a/indra/newview/llteleporthistorystorage.h b/indra/newview/llteleporthistorystorage.h index 946ac0af1aaed473bb4fd6e1adce22ae1a985708..c646bb7edfd49c5e6fff6a9c45f531f451be6784 100644 --- a/indra/newview/llteleporthistorystorage.h +++ b/indra/newview/llteleporthistorystorage.h @@ -107,7 +107,11 @@ class LLTeleportHistoryStorage: public LLSingleton<LLTeleportHistoryStorage> */ void goToItem(S32 idx); -private: +//private: +// [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) | Added: RLVa-1.2.1b +protected: + friend class RlvUIEnabler; +// [/RLVa:KB] void load(); void dump() const; diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 100d5ee71359327311d51073058502fc5ad60373..6efd667a024356cf56a529d575750a5ec8b00289 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -55,7 +55,10 @@ LLToastPanel::~LLToastPanel() std::string LLToastPanel::getTitle() { // *TODO: create Title and localize it. If it will be required. - return mNotification->getMessage(); +// return mNotification->getMessage(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a + return (mNotification->hasLabel()) ? mNotification->getLabel() : mNotification->getMessage(); +// [/SL:KB] } //virtual diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 7d77a8983f7de8b9ec32d22fa838230922ddebf2..04066ebf95c602f05c84afbf8998d095596356a7 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -60,6 +60,10 @@ #include "llvoavatarself.h" #include "llworld.h" #include "llpanelface.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] // syntactic sugar #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember)) @@ -1236,6 +1240,15 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, return; } + +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a + // Fallback in case there's a new code path that leads here (see behaviour notes) + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) + { + return; + } +// [/RLVa:KB] + //LL_INFOS() << "Rezzing object" << LL_ENDL; make_ui_sound("UISndObjectRezIn"); LLViewerInventoryItem* item; @@ -1513,6 +1526,23 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL BOOL volume = (LL_PCODE_VOLUME == obj->getPCode()); BOOL attached = obj->isAttachment(); BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; + +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0c + if (rlv_handler_t::isEnabled()) + { + const LLViewerObject* pObjRoot = obj->getRootEdit(); + if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot)) + { + return ACCEPT_NO_LOCKED; // Disallow inventory drops on a locked attachment + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) ) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObjRoot) ) + return ACCEPT_NO_LOCKED; // ... or on a linkset the avie is sitting on under @unsit=n/@sittp=n + } + } +// [/RLVa:KB] + if(attached && !unrestricted) { return ACCEPT_NO_LOCKED; @@ -1732,12 +1762,23 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( return ACCEPT_NO; } +// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8) + bool fReplace = !(mask & MASK_CONTROL); + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item, (fReplace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] if( drop ) { if(mSource == SOURCE_LIBRARY) { - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0)); +// LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0)); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-2.2) + // Make this behave consistent with dad3dWearItem + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, fReplace)); +// [/SL:KB] copy_inventory_item( gAgent.getID(), item->getPermissions().getOwner(), @@ -1748,7 +1789,11 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( } else { - rez_attachment(item, 0); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-2.2) + // Make this behave consistent with dad3dWearItem + rez_attachment(item, 0, !(mask & MASK_CONTROL)); +// [/SL:KB] +// rez_attachment(item, 0); } } return ACCEPT_YES_SINGLE; @@ -1758,6 +1803,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // RELEASE-RLVa: [SL-2.2.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnLand() + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + if (mSource == SOURCE_WORLD) { return dad3dRezFromObjectOnLand(obj, face, mask, drop); @@ -1819,6 +1872,18 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // NOTE: if (mask & MASK_CONTROL) then it's a drop rather than a rez, so we let that pass through when @rez=n restricted + // (but not when @interact=n restricted unless the drop target is a HUD attachment) + // RELEASE-RLVa: [SL-2.2.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnObject() + if ( (rlv_handler_t::isEnabled()) && + ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) && ((mask & MASK_CONTROL) == 0) ) || + ( (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (((mask & MASK_CONTROL) == 0) || (!obj->isHUDAttachment())) ) ) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + // handle objects coming from object inventory if (mSource == SOURCE_WORLD) { @@ -2049,11 +2114,22 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( return ACCEPT_NO; } +// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8) + bool fReplace = (!(mask & MASK_CONTROL)) || (LLAssetType::AT_BODYPART == item->getType()); // Body parts should always replace + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item, (fReplace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) + { + return ACCEPT_NO_LOCKED; + } +// [/RLVa:KB] + if( drop ) { // TODO: investigate wearables may not be loaded at this point EXT-8231 - LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL)); +// [RLVa:KB] - Checked: 2013-02-13 (RLVa-1.4.8) + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, fReplace); +// [/RLVa:KB] +// LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL)); } return ACCEPT_YES_MULTI; } diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index a00ac10698a9798958d9d435e483c01463eef503..f380de18377f1439408206d3fd779ca23e3dd5aa 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -39,6 +39,9 @@ #include "llviewerobject.h" #include "llviewerwindow.h" #include "llfloatertools.h" +// [RLVa:KB] - Checked: RLVa-2.1.0 +#include "rlvactions.h" +// [/RLVa:KB] // // Member functions @@ -90,6 +93,13 @@ void LLToolFace::pickCallback(const LLPickInfo& pick_info) return; } +// [RLVa:KB] - Checked: RLVa-1.3.0 + if ( (RlvActions::isRlvEnabled()) && ((!RlvActions::canEdit(hit_obj)) || (!RlvActions::canInteract(hit_obj, pick_info.mObjectOffset))) ) + { + return; + } +// [/RLVa:KB] + // ...clicked on a world object, try to pick the appropriate face if (pick_info.mKeyMask & MASK_SHIFT) diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index a4806ceaf64df5834687b2bbbe401f9778b62d86..bc5cee6f540941ad578478f431c65f10a132220b 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -57,6 +57,9 @@ #include "llvoavatarself.h" #include "llworld.h" #include "llmenugl.h" +// [RLVa:KB] - Checked: RLVa-2.1.0 +#include "rlvactions.h" +// [/RLVa:KB] const S32 SLOP_DIST_SQ = 4; @@ -170,7 +173,11 @@ void LLToolGrabBase::pickCallback(const LLPickInfo& pick_info) } // if not over object, do nothing - if (!objectp) +// if (!objectp) +// [RLVa:KB] - Checked: RLVa-1.1.0 + // Block initiating a drag operation on an object that can't be touched + if ( (!objectp) || ((RlvActions::isRlvEnabled()) && (!RlvActions::canTouch(objectp, pick_info.mObjectOffset))) ) +// [/RLVa:KB] { LLToolGrab::getInstance()->setMouseCapture(TRUE); LLToolGrab::getInstance()->mMode = GRAB_NOOBJECT; @@ -431,6 +438,21 @@ BOOL LLToolGrabBase::handleHover(S32 x, S32 y, MASK mask) return TRUE; } +// [RLVa:KB] - Checked: RLVa-1.1.0 + // Block dragging an object beyond touch range + if ( (RlvActions::isRlvEnabled()) && (GRAB_INACTIVE != mMode) && (GRAB_NOOBJECT != mMode) && (hasMouseCapture()) && (!RlvActions::canTouch(mGrabPick.getObject(), mGrabPick.mObjectOffset)) ) + { + if (gGrabTransientTool) + { + // Prevent the grab tool from popping up as soon as we kill the drag operation + gBasicToolset->selectTool(gGrabTransientTool); + gGrabTransientTool = NULL; + } + setMouseCapture(FALSE); + return TRUE; + } +// [/RLVa:KB] + // Do the right hover based on mode switch( mMode ) { diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp index 6c9155be851675281d6fccc722c0cd2d25bc8571..3d72976c96f9780ac6b3984443ba440c19120148 100644 --- a/indra/newview/lltoolgun.cpp +++ b/indra/newview/lltoolgun.cpp @@ -39,6 +39,9 @@ #include "llui.h" #include "llviewertexturelist.h" #include "llviewercamera.h" +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) +#include "llfocusmgr.h" +// [/RLVa:KB] #include "llhudmanager.h" #include "lltoolmgr.h" #include "lltoolgrab.h" @@ -54,10 +57,17 @@ LLToolGun::LLToolGun( LLToolComposite* composite ) void LLToolGun::handleSelect() { - gViewerWindow->hideCursor(); - gViewerWindow->moveCursorToCenter(); - gViewerWindow->getWindow()->setMouseClipping(TRUE); - mIsSelected = TRUE; +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + if (gFocusMgr.getAppHasFocus()) + { +// [/RLVa:KB] + gViewerWindow->hideCursor(); + gViewerWindow->moveCursorToCenter(); + gViewerWindow->getWindow()->setMouseClipping(TRUE); + mIsSelected = TRUE; +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + } +// [/RLVa:KB] } void LLToolGun::handleDeselect() diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index 3fcf193deca2f4688744f41cd14b7798f43e1b39..ae6547b77ee8866dba23ba11749e60d119baf8cc 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -57,7 +57,10 @@ #include "llviewerjoystick.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" - +// [RLVa:KB] - Checked: RLVa-2.1.0 +#include "llfloatertools.h" +#include "rlvactions.h" +// [/RLVa:KB] // Used when app not active to avoid processing hover. LLTool* gToolNull = NULL; @@ -262,7 +265,10 @@ bool LLToolMgr::inEdit() bool LLToolMgr::canEdit() { - return LLViewerParcelMgr::getInstance()->allowAgentBuild(); +// [RLVa:KB] - Patch: RLVa-2.1.0 + return LLViewerParcelMgr::getInstance()->allowAgentBuild() && RlvActions::canBuild(); +// [/RLVa:KB] +// return LLViewerParcelMgr::getInstance()->allowAgentBuild(); } bool LLToolMgr::buildEnabledOrActive() @@ -272,17 +278,43 @@ bool LLToolMgr::buildEnabledOrActive() void LLToolMgr::toggleBuildMode(const LLSD& sdname) { - const std::string& param = sdname.asString(); +// const std::string& param = sdname.asString(); +// +// LLFloaterReg::toggleInstanceOrBringToFront("build"); +// if (param == "build" && !canEdit()) +// { +// return; +// } +// +// bool build_visible = LLFloaterReg::instanceVisible("build"); +// if (build_visible) +// { +// [RLVa:KB] - Checked: RLVa-2.1.0 + if (gFloaterTools) + { + if (gFloaterTools->isShown()) + leaveBuildMode(); + else + enterBuildMode("build" == sdname.asString()); + } +} + +void LLToolMgr::enterBuildMode(bool verify_canedit /*=false*/) +{ + if (!gFloaterTools) + return; + if (!gFloaterTools->isShown()) + gFloaterTools->openFloater(); + if (!gFloaterTools->isFrontmost()) + gFloaterTools->setVisibleAndFrontmost(true); - LLFloaterReg::toggleInstanceOrBringToFront("build"); - if (param == "build" && !canEdit()) + if (verify_canedit && !canEdit()) { return; } - bool build_visible = LLFloaterReg::instanceVisible("build"); - if (build_visible) { +// [/RLVa:KB] ECameraMode camMode = gAgentCamera.getCameraMode(); if (CAMERA_MODE_MOUSELOOK == camMode || CAMERA_MODE_CUSTOMIZE_AVATAR == camMode) { @@ -321,7 +353,20 @@ void LLToolMgr::toggleBuildMode(const LLSD& sdname) LLViewerJoystick::getInstance()->setNeedsReset(); } - else +// [RLVa:KB] - Checked: RLVa-2.1.0 +} +// [/RLVa:KB] +// else +// [RLVa:KB] - Checked: RLVa-2.1.0 +void LLToolMgr::leaveBuildMode() +{ + if ( (!gFloaterTools) || (!gFloaterTools->getVisible()) ) + { + return; + } + + gFloaterTools->closeFloater(); +// [/RLVa:KB] { if (gSavedSettings.getBOOL("EditCameraMovement")) { diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index 28465d5d2cd1e83de8cbe1829bfd840822413fe9..d5ec645949cbe120369d9286d090171ae5573bf6 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -57,6 +57,10 @@ class LLToolMgr : public LLSingleton<LLToolMgr> bool buildEnabledOrActive(); bool canAccessMarketplace(); void toggleBuildMode(const LLSD& sdname); +// [RLVa:KB] - Checked: RLVa-2.1.0 + void enterBuildMode(bool verify_canedit = false); + void leaveBuildMode(); +// [/RLVa:KB] void toggleMarketplace(const LLSD& sdname); /* Determines if we are in Build mode or not. */ diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index aeb8bdc496dd4d3535f83a1165bf4ee310267b27..214450bebaa866236ca750630d1ceb1d43630377 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -70,6 +70,10 @@ #include "llui.h" #include "llweb.h" #include "pipeline.h" // setHighlightObject +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) +#include "rlvactions.h" +#include "rlvhandler.h" +// [/RLVa:KB] extern BOOL gDebugClicks; @@ -265,6 +269,14 @@ BOOL LLToolPie::handleLeftClickPick() // If it's a left-click, and we have a special action, do it. if (useClickAction(mask, object, parent)) { +// [RLVa:KB] - Checked: RLVa-1.1.0 + // Blanket block all left-click special actions on objects the user can't interact with + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canInteract(object, mPick.mObjectOffset)) ) + { + return TRUE; + } +// [/RLVa:KB] + mClickAction = 0; if (object && object->getClickAction()) { @@ -388,6 +400,14 @@ BOOL LLToolPie::handleLeftClickPick() ((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable) ) { +// [RLVa:KB] - Checked: RLVa-1.1.0 + // Triggered by left-clicking on a touchable object + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canTouch(object, mPick.mObjectOffset)) ) + { + return LLTool::handleMouseDown(x, y, mask); + } +// [/RLVa:KB] + gGrabTransientTool = this; mMouseButtonDown = false; LLToolGrab::getInstance()->setClickedInMouselook(gAgentCamera.cameraMouselook()); @@ -488,7 +508,11 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object) { case CLICK_ACTION_SIT: { - if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting? +// if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting? +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0g + if ( (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) && + ((!rlv_handler_t::isEnabled()) || (RlvActions::canSit(object, LLToolPie::getInstance()->getHoverPick().mObjectOffset))) ) +// [/RLVa:KB] { cursor = UI_CURSOR_TOOLSIT; } @@ -611,6 +635,14 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); +// [RLVa:KB] - Checked: RLVa-1.1.0 + // Blanket block all left-click special actions on objects the user can't interact with + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canInteract(object, mHoverPick.mObjectOffset)) ) + { + gViewerWindow->setCursor(UI_CURSOR_ARROW); + return TRUE; + } +// [/RLVa:KB] LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace); if (object) { @@ -665,7 +697,13 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->setCursor(cursor); LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } - +// [RLVa:KB] - Checked: RLVa-1.1.0 + else if ( (object) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTouch(object, mHoverPick.mObjectOffset)) ) + { + // Block showing the "grab" or "touch" cursor if we can't touch/grab the object + gViewerWindow->setCursor(UI_CURSOR_ARROW); + } +// [/RLVa:KB] else if ((object && !object->isAvatar() && object->flagUsePhysics()) || (parent && !parent->isAvatar() && parent->flagUsePhysics())) { @@ -743,10 +781,24 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) FALSE /* ignore rigged */, FALSE /* ignore particles */); - if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick - && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land - || mPick.mObjectID.notNull())) // or on an object +// if (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick +// && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land +// || mPick.mObjectID.notNull())) // or on an object +// [RLVa:KB] - Checked: RLVa-2.0.0 + bool fValidPick = (!mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick + && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land + || mPick.mObjectID.notNull())); // or on an object + + if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT); + fValidPick = false; + } + + if (fValidPick) +// [/RLVa:KB] { + // handle special cases of steering picks LLViewerObject* avatar_object = mPick.getObject(); @@ -842,8 +894,20 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) } } - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) +// if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || +// (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) +// [RLVa:KB] - Checked: RLVa-2.0.0 + bool fValidPick = ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())); + + if ( (fValidPick) && (RlvActions::isRlvEnabled()) && (!RlvActions::canTeleportToLocal(mPick.mPosGlobal)) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_AUTOPILOT); + fValidPick = false; + } + + if (fValidPick) +// [/RLVa:KB] { walkToClickedLocation(); return TRUE; @@ -1085,7 +1149,10 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l LLAvatarName av_name; if (LLAvatarNameCache::get(hover_object->getID(), &av_name)) { - final_name = av_name.getCompleteName(); +// [RLVa:KB] - Checked: RLVa-1.2.2 + final_name = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, hover_object->getID())) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] +// final_name = av_name.getCompleteName(); } else { @@ -1094,17 +1161,29 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l // *HACK: We may select this object, so pretend it was clicked mPick = mHoverPick; - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(final_name); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showAvatarInspector, hover_object->getID())); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay")); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (!RlvActions::isRlvEnabled()) || + ( (RlvActions::canInteract(hover_object, mHoverPick.mObjectOffset)) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, hover_object->getID())) ) ) + { +// [/RLVa:KB] + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(final_name); + p.image.name("Inspector_I"); + p.click_callback(boost::bind(showAvatarInspector, hover_object->getID())); + p.visible_time_near(6.f); + p.visible_time_far(3.f); + p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay")); + p.wrap(false); + + LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: RLVa-1.2.0 + } +// else +// { +// LLToolTipMgr::instance().show(final_name); +// } +// [/RLVa:KB] } } else @@ -1207,22 +1286,33 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l { // We may select this object, so pretend it was clicked mPick = mHoverPick; - LLInspector::Params p; - p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); - p.message(tooltip_msg); - p.image.name("Inspector_I"); - p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace)); - p.time_based_media(is_time_based_media); - p.web_based_media(is_web_based_media); - p.media_playing(is_media_playing); - p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick)); - p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick)); - p.visible_time_near(6.f); - p.visible_time_far(3.f); - p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay")); - p.wrap(false); - - LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: RLVa-1.2.1 + if ( (!RlvActions::isRlvEnabled()) || (RlvActions::canInteract(hover_object, mHoverPick.mObjectOffset)) ) + { +// [/RLVa:KB] + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(tooltip_msg); + p.image.name("Inspector_I"); + p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace)); + p.time_based_media(is_time_based_media); + p.web_based_media(is_web_based_media); + p.media_playing(is_media_playing); + p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick)); + p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick)); + p.visible_time_near(6.f); + p.visible_time_far(3.f); + p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay")); + p.wrap(false); + + LLToolTipMgr::instance().show(p); +// [RLVa:KB] - Checked: RLVa-2.1.0 + } +// else +// { +// LLToolTipMgr::instance().show(tooltip_msg); +// } +// [/RLVa:KB] } } } @@ -1236,7 +1326,15 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask) if (!mHoverPick.isValid()) return TRUE; LLViewerObject* hover_object = mHoverPick.getObject(); - + +// [RLVa:KB] - Checked: RLVa-2.1.0 + // Block the tooltip of anything the user can't interact with + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canInteract(hover_object, mHoverPick.mObjectOffset)) ) + { + return TRUE; + } +// [/RLVa:KB] + // update hover object and hover parcel LLSelectMgr::getInstance()->setHoverObject(hover_object, mHoverPick.mObjectFace); @@ -1820,16 +1918,29 @@ BOOL LLToolPie::handleRightClickPick() mute_msg = LLTrans::getString("MuteAvatar"); } - if (is_other_attachment) +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // Don't show the context menu on empty selection when fartouch restricted [see LLToolSelect::handleObjectSelection()] + if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) || + (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ) { - gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); - gMenuAttachmentOther->show(x, y); +// [/RLVa:KB] + if (is_other_attachment) + { + gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); + gMenuAttachmentOther->show(x, y); + } + else + { + gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); + gMenuAvatarOther->show(x, y); + } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l } else { - gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg); - gMenuAvatarOther->show(x, y); + make_ui_sound("UISndInvalidOp"); } +// [/RLVa:KB] } else if (object->isAttachment()) { @@ -1845,9 +1956,23 @@ BOOL LLToolPie::handleRightClickPick() name = node->mName; } - gMenuObject->show(x, y); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l + // Don't show the pie menu on empty selection when fartouch/interaction restricted + // (not entirely accurate in case of Tools / Select Only XXX [see LLToolSelect::handleObjectSelection()] + if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) || + (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ) + { +// [/RLVa:KB] + gMenuObject->show(x, y); - showVisualContextMenuEffect(); + showVisualContextMenuEffect(); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l + } + else + { + make_ui_sound("UISndInvalidOp"); + } +// [/RLVa:KB] } } else if (mPick.mParticleOwnerID.notNull()) diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index fe0acfe47305e6c1cdb7eba830fb8316cc1f547b..373694443ffc195cfdb52408b168148ef2e93fd5 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -63,6 +63,9 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie> virtual LLTool* getOverrideTool(MASK mask); LLPickInfo& getPick() { return mPick; } +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a + LLPickInfo& getHoverPick() { return mHoverPick; } +// [/RLVa:KB] U8 getClickAction() { return mClickAction; } LLViewerObject* getClickActionObject() { return mClickActionObject; } LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 814bade56ad675f882e2cb763cd78b7de0349cac..864d0d77b02534731af8df5d1a3cd0161d240670 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -43,6 +43,10 @@ #include "llviewerwindow.h" #include "llworld.h" #include "llui.h" +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) +#include "rlvhandler.h" +#include "rlvmodifiers.h" +// [/RLVa:KB] //Headers added for functions moved from viewer.cpp #include "llvograss.h" @@ -123,6 +127,16 @@ BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, return FALSE; } +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f + // NOTE: don't use surface_pos_global since for prims it will be the center of the prim while we need center + offset + if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) + { + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + if (dist_vec_squared(gAgent.getPositionGlobal(), pick.mPosGlobal) > s_nFartouchDist * s_nFartouchDist) + return FALSE; + } +// [/RLVa:KB] + // Find the sim where the surface lives. LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); if (!regionp) @@ -240,7 +254,10 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) { flags |= FLAGS_USE_PHYSICS; } - if (create_selected) +// if (create_selected) +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.0.0b + if ( (create_selected) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) ) +// [/RLVa:KB] { flags |= FLAGS_CREATE_SELECTED; } @@ -498,6 +515,13 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) { BOOL added = TRUE; +// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) ) + { + return TRUE; // Callers seem to expect a "did you handle it?" so we return TRUE rather than FALSE + } +// [/RLVa:KB] + if (gSavedSettings.getBOOL("CreateToolCopySelection")) { added = addDuplicate(x, y); diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index e52bc0b015a131179433b6827463edf2ca8bf42c..3a956aaa91d16c9b3e7171e7cbfc829d90e2afb1 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -47,6 +47,11 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvmodifiers.h" +#include "llfloaterreg.h" +// [/RLVa:KB] // Globals //extern BOOL gAllowSelectAvatar; @@ -82,6 +87,44 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi { object = object->getRootEdit(); } + +// [RLVa:KB] - Checked: RLVa-2.1.0 + if ( (object) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canEdit(object)) + { + if (!temp_select) + return LLSelectMgr::getInstance()->getSelection(); + else if (LLToolMgr::instance().inBuildMode()) + LLToolMgr::instance().leaveBuildMode(); + } + + if ( (RlvActions::hasBehaviour(RLV_BHVR_FARTOUCH)) && ( (!object->isAttachment()) || (!object->permYouOwner())) ) + { + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + float nFartouchDistSq = s_nFartouchDist * s_nFartouchDist; + + // User is allowed to edit/select this object if it's within their current fartouch distance + if (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion()) > nFartouchDistSq) + { + // The object is out of range but we'll still allow them a temporary select (e.g. context menu) if the surface point is within range + if (dist_vec_squared(gAgent.getPositionAgent(), pick.mIntersection) > 1.5f * 1.5f) + { + // Even the surface point is out of range so deny them the hit + if ( (LLFloaterReg::instanceVisible("build")) && (pick.mKeyMask != MASK_SHIFT) && (pick.mKeyMask != MASK_CONTROL) ) + LLSelectMgr::getInstance()->deselectAll(); + return LLSelectMgr::getInstance()->getSelection(); + } + else if (LLToolMgr::instance().inBuildMode()) + { + // Allow the selection but keep it temporary by pulling them out of build mode when they click too far + LLToolMgr::instance().leaveBuildMode(); + } + } + } + } +// [/RLVa:KB] + BOOL select_owned = gSavedSettings.getBOOL("SelectOwnedOnly"); BOOL select_movable = gSavedSettings.getBOOL("SelectMovableOnly"); diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 2ec5c41b8862ca77dc0841edc9f8eeb80d5ab771..b0179d65a06f27f416f9989286a7218607a80b13 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -62,6 +62,7 @@ #include "llworldmapview.h" #include "llviewercontrol.h" + const F32 DESTINATION_REACHED_RADIUS = 3.0f; const F32 DESTINATION_VISITED_RADIUS = 6.0f; diff --git a/indra/newview/llviewerattachmenu.cpp b/indra/newview/llviewerattachmenu.cpp index 3975292ed3a6e7871384b9d21cebbfbf39876008..2d015fc8c1f4b681708ba1828a67e6ea1705ddb2 100644 --- a/indra/newview/llviewerattachmenu.cpp +++ b/indra/newview/llviewerattachmenu.cpp @@ -121,7 +121,10 @@ void LLViewerAttachMenu::attachObjects(const uuid_vec_t& items, const std::strin else if(item && item->isFinished()) { // must be in library. copy it to our inventory and put it on. - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp)); +// LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp)); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2013-02-04 (Catznip-3.4) + LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp, false)); +// [/SL;KB] copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(), diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 778e27572728557f3269cdf06642c56f25398ee6..18895195a3482bec35cc5ab5e773696df9dd5157 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -41,6 +41,9 @@ #include "llworld.h" #include "lltoolmgr.h" #include "llviewerjoystick.h" +// [RLVa:KB] - RLVa-2.0.0 +#include "rlvactions.h" +// [/RLVa:KB] // Linden library includes #include "lldrawable.h" @@ -360,6 +363,11 @@ void LLViewerCamera::setPerspective(BOOL for_selection, { z_far = gAgentCamera.mDrawDistance; } + +// [RLVa:KB] - Checked: RLVa-2.0.0 + if (RlvActions::hasBehaviour(RLV_BHVR_FARTOUCH)) + z_far = RlvActions::getModifierValue<float>(RLV_MODIFIER_FARTOUCHDIST); +// [/RLVa:KB] } else { @@ -877,6 +885,12 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) { +// [RLVa:KB] - Checked: RLVa-2.0.0 + F32 nCamFOVMin, nCamFOVMax; + if ( (RlvActions::isRlvEnabled()) && (RlvActions::getCameraFOVLimits(nCamFOVMin, nCamFOVMax)) ) + vertical_fov_rads = llclamp(vertical_fov_rads, nCamFOVMin, nCamFOVMax); +// [/RLVa:KB] + vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView()); setView(vertical_fov_rads); mCameraFOVDefault = vertical_fov_rads; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index a699491e1bfbca510a86823b93b8d05aacd125e7..dc984694be76d2a55356a782a4b861e8b2b318fc 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -75,6 +75,9 @@ #include "llspellcheck.h" #include "llslurl.h" #include "llstartup.h" +// [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0) +#include "rlvcommon.h" +// [/RLVa:KB] // Third party library includes #include <boost/algorithm/string.hpp> @@ -643,6 +646,9 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2)); gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2)); gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2)); +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + gSavedSettings.getControl("RenderResolutionMultiplier")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2)); +// [/SL:KB] gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2)); gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); @@ -748,6 +754,9 @@ void settings_setup_listeners() gSavedSettings.getControl("DebugAvatarJoints")->getCommitSignal()->connect(boost::bind(&handleDebugAvatarJointsChanged, _2)); gSavedSettings.getControl("RenderAutoMuteByteLimit")->getSignal()->connect(boost::bind(&handleRenderAutoMuteByteLimitChanged, _2)); gSavedPerAccountSettings.getControl("AvatarHoverOffsetZ")->getCommitSignal()->connect(boost::bind(&handleAvatarHoverOffsetChanged, _2)); +// [RLVa:KB] - Checked: 2015-12-27 (RLVa-1.5.0) + gSavedSettings.getControl("RestrainedLove")->getSignal()->connect(boost::bind(&RlvSettings::onChangedSettingMain, _2)); +// [/RLVa:KB] } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 6df849674f26b56349b38b5ce5d4553ce43a1363..be2fd55d7a769b7f86dd442fef703e97e45b3e5b 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -78,6 +78,10 @@ #include "llwaterparammanager.h" #include "llpostprocess.h" #include "llscenemonitor.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] extern LLPointer<LLViewerTexture> gStartTexture; extern bool gShiftFrame; @@ -502,6 +506,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // No teleport in progress gViewerWindow->setShowProgress(FALSE); gTeleportDisplay = FALSE; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + LLViewerParcelMgr::getInstance()->onTeleportDone(); +// [/SL:KB] break; } } @@ -1085,7 +1092,11 @@ void render_hud_attachments() glh::matrix4f current_mod = glh_get_current_modelview(); // clamp target zoom level to reasonable values - gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); +// gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c + gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f); +// [/RLVa:KB] + // smoothly interpolate current zoom level gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.getAgentHUDTargetZoom(), LLSmoothInterpolation::getInterpolant(0.03f)); @@ -1298,6 +1309,12 @@ void render_ui(F32 zoom_factor, int subfield) LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD); render_hud_elements(); +// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) + if (gRlvHandler.isEnabled()) + { + gRlvHandler.renderOverlay(); + } +// [/RLVa:KB] render_hud_attachments(); } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index bbd5251ed234243e70afdc5d8cc49cde096af575..4f828044e8e6d06d2a30c2f5e65ba7251a8c7a47 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -160,7 +160,9 @@ #include "llsyswellwindow.h" // *NOTE: Please add files in alphabetical order to keep merges easy. - +// [RLVa:KB] - Checked: 2010-03-11 +#include "rlvfloaters.h" +// [/RLVa:KB] // handle secondlife:///app/openfloater/{NAME} URLs class LLFloaterOpenHandler : public LLCommandHandler { @@ -332,6 +334,12 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("region_debug_console", "floater_region_debug_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionDebugConsole>); LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>); LLFloaterReg::add("region_restarting", "floater_region_restarting.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionRestarting>); +// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0a + LLFloaterReg::add("rlv_behaviours", "floater_rlv_behaviours.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterBehaviours>); + LLFloaterReg::add("rlv_console", "floater_rlv_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterConsole>); + LLFloaterReg::add("rlv_locks", "floater_rlv_locks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterLocks>); + LLFloaterReg::add("rlv_strings", "floater_rlv_strings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterStrings>); +// [/RLVa:KB] LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>); LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 6ff02ffe66b3999b13c011993e35e31f2376b5ee..872476b6d9b69fcb000de59531f4a0e0e05f36eb 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -70,6 +70,9 @@ #include "llfloaterperms.h" #include "llclipboard.h" #include "llhttpretrypolicy.h" +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) +#include "rlvcommon.h" +// [/RLVa:KB] // do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} @@ -998,7 +1001,10 @@ void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id) } } -void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp) +//void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp) +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) +void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace) +// [/SL:KB] { if (inv_item.isNull()) return; @@ -1006,7 +1012,10 @@ void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachme LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (item) { - rez_attachment(item, attachmentp); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) + rez_attachment(item, attachmentp, replace); +// [/SL:KB] +// rez_attachment(item, attachmentp); } } @@ -1706,6 +1715,65 @@ void create_new_item(const std::string& name, cb); } +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) +void sync_inventory_folder(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLInventoryModel::item_array_t& items_to_add, LLInventoryModel::item_array_t& items_to_remove) +{ + LLInventoryModel::item_array_t curItems, newItems = items; + + // Grab the current contents + LLInventoryModel::cat_array_t cats; + gInventory.collectDescendents(folder_id, cats, curItems, LLInventoryModel::EXCLUDE_TRASH); + + // Purge everything in curItems that isn't part of newItems + for (LLInventoryModel::item_array_t::const_iterator itCurItem = curItems.begin(); itCurItem != curItems.end(); ++itCurItem) + { + LLViewerInventoryItem* pItem = *itCurItem; + if (std::find_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) == newItems.end()) + { + // Item doesn't exist in newItems => purge (if it's a link) + if ( (pItem->getIsLinkType()) && + (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) && + (items_to_remove.end() == std::find(items_to_remove.begin(), items_to_remove.end(), pItem)) ) + { + items_to_remove.push_back(pItem); + } + } + else + { + // Item exists in newItems => remove *all* occurances in newItems (removes duplicate COF links to this item as well) + newItems.erase(std::remove_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), newItems.end()); + } + } + + // Whatever remains in newItems will need to have a link created + for (LLInventoryModel::item_array_t::const_iterator itNewItem = newItems.begin(); itNewItem != newItems.end(); ++itNewItem) + { + LLViewerInventoryItem* pItem = *itNewItem; + if (items_to_add.end() == std::find(items_to_add.begin(), items_to_add.end(), pItem)) + items_to_add.push_back(pItem); + } +} + +void link_inventory_items(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb) +{ + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + link_inventory_object(folder_id, pItem, cb); + } +} + +void remove_inventory_items(const LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb) +{ + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem->getIsLinkType()) + remove_inventory_item(pItem->getUUID(), cb); + } +} +// [/RLVa:KB] + void slam_inventory_folder(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> cb) diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index b3053e365bd2ce49a052338b9947b8636486bbe7..4ebb885cb918d3e01db8cafda5e4e425cc2469f6 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -253,7 +253,10 @@ class LLInventoryCallback : public LLRefCount class LLViewerJointAttachment; -void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) +void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace); +// [/SL:KB] +//void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp); void activate_gesture_cb(const LLUUID& inv_item); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 8a597ed7e65147c5c862ec3ed41b645f31b56944..738045b8db3c94dd19f0c7fc80894ad211cf83f5 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -28,6 +28,9 @@ #include "llviewerjointattachment.h" +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 +#include "llagent.h" +// [/SL:KB] #include "llviewercontrol.h" #include "lldrawable.h" #include "llgl.h" @@ -166,28 +169,56 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) //----------------------------------------------------------------------------- BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) { - object->extractAttachmentItemID(); +// object->extractAttachmentItemID(); // Same object reattached if (isObjectAttached(object)) { LL_INFOS() << "(same object re-attached)" << LL_ENDL; +//// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +// if ( (object->permYouOwner()) && (gAgentAvatarp) ) +// { +// gAgentAvatarp->removePendingDetach(object->getID()); +// } +//// [/SL:KB] removeObject(object); // Pass through anyway to let setupDrawable() // re-connect object to the joint correctly } +// [SL:KB] - Patch: Appearance-Misc | Checked: 2011-01-13 (Catznip-2.4) + // LLViewerJointAttachment::removeObject() sets the object's item to the NULL UUID so we need to extract it *after* the block above + object->extractAttachmentItemID(); +// [/SL:KB] + // Two instances of the same inventory item attached -- // Request detach, and kill the object in the meantime. - if (getAttachedObject(object->getAttachmentItemID())) +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 + if (LLViewerObject* pAttachObj = getAttachedObject(object->getAttachmentItemID())) { LL_INFOS() << "(same object re-attached)" << LL_ENDL; - object->markDead(); - - // If this happens to be attached to self, then detach. - LLVOAvatarSelf::detachAttachmentIntoInventory(object->getAttachmentItemID()); - return FALSE; - } + pAttachObj->markDead(); + if (pAttachObj->permYouOwner()) + { + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID()); + gMessageSystem->sendReliable(gAgent.getRegionHost()); + } + } +// [/SL:KB] +// if (getAttachedObject(object->getAttachmentItemID())) +// { +// LL_INFOS() << "(same object re-attached)" << LL_ENDL; +// object->markDead(); +// +// // If this happens to be attached to self, then detach. +// LLVOAvatarSelf::detachAttachmentIntoInventory(object->getAttachmentItemID()); +// return FALSE; +// } mAttachedObjects.push_back(object); setupDrawable(object); @@ -461,7 +492,10 @@ const LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &o ++iter) { const LLViewerObject* attached_object = iter->get(); - if (attached_object->getAttachmentItemID() == object_id) +// if (attached_object->getAttachmentItemID() == object_id) +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 + if ( (attached_object->getAttachmentItemID() == object_id) && (!attached_object->isDead()) ) +// [/SL:KB] { return attached_object; } diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e44d80b7ceab33405c2bdbbc52c6cb9ffdea8ce3..06e1e64300527a18a9772fdee8bbef7f879903ff 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -326,8 +326,11 @@ void LLViewerJoystick::handleRun(F32 inc) if (1 == mJoystickRun) { ++mJoystickRun; - gAgent.setRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); +// gAgent.setRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.setTempRun(); +// [/RLVa:KB] } else if (0 == mJoystickRun) { @@ -342,8 +345,11 @@ void LLViewerJoystick::handleRun(F32 inc) --mJoystickRun; if (0 == mJoystickRun) { - gAgent.clearRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); +// gAgent.clearRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.clearTempRun(); +// [/RLVa:KB] } } } diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index e930eb20d3cf185affae53bb182d622dc0a0b2d3..5a442eb4bc99549c942b46cbf43dcfe6ab1949c7 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -96,14 +96,18 @@ void agent_push_down( EKeystate s ) static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode) { - if (gAgent.mDoubleTapRunMode == mode && - gAgent.getRunning() && - !gAgent.getAlwaysRun()) - { - // Turn off temporary running. - gAgent.clearRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); - } +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) ) + gAgent.clearTempRun(); +// [/RLVa:KB] +// if (gAgent.mDoubleTapRunMode == mode && +// gAgent.getRunning() && +// !gAgent.getAlwaysRun()) +// { +// // Turn off temporary running. +// gAgent.clearRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// } } static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) @@ -123,8 +127,11 @@ static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode m { // Same walk-key was pushed again quickly; this is a // double-tap so engage temporary running. - gAgent.setRunning(); - gAgent.sendWalkRun(gAgent.getRunning()); +// gAgent.setRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.setTempRun(); +// [/RLVa:KB] } // Pressing any walk-key resets the double-tap timer diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 99b54f66d35e0c014b0bde0b9c41087520c21388..c36e6960b01b92c6f7659cead1cc3a97464ca3ef 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2910,7 +2910,10 @@ void LLViewerMediaImpl::updateImagesMediaStreams() ////////////////////////////////////////////////////////////////////////////////////////// LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() { - if(mTextureId.isNull()) +// if(mTextureId.isNull()) +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + if ( (mTextureId.isNull()) || ((LLViewerFetchedTexture::sDefaultDiffuseImagep.notNull()) && (LLViewerFetchedTexture::sDefaultDiffuseImagep->getID() == mTextureId)) ) +// [/SL:KB] { // The code that created this instance will read from the plugin's bits. return NULL; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index f859ced3425d0c82e943cf31b8d69f0a73967e93..6ee6c6de7dcbe182c9348af5cfa5467a1b749553 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -49,6 +49,9 @@ #include "llagentui.h" #include "llagentwearables.h" #include "llagentpilot.h" +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 +#include "llattachmentsmgr.h" +// [/SL:KB] #include "llcompilequeue.h" #include "llconsole.h" #include "lldaycyclemanager.h" @@ -135,6 +138,11 @@ #include "boost/unordered_map.hpp" #include <boost/regex.hpp> #include "llcleanup.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvlocks.h" +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; @@ -1218,11 +1226,27 @@ class LLAdvancedToggleWireframe : public view_listener_t { bool handleEvent(const LLSD& userdata) { - gUseWireframe = !(gUseWireframe); +// [RLVa:KB] - Checked: RLVa-2.0.0 + bool fRlvBlockWireframe = gRlvAttachmentLocks.hasLockedHUD(); + if ( (!gUseWireframe) && (fRlvBlockWireframe) ) + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_WIREFRAME); + set_use_wireframe( (!gUseWireframe) && (!fRlvBlockWireframe) ); + return true; + } +}; + +// Called from rlvhandler.cpp +void set_use_wireframe(bool useWireframe) + { + if (gUseWireframe == useWireframe) + return; + + gUseWireframe = useWireframe; +// [/RLVa:KB] +// gUseWireframe = !(gUseWireframe); gWindowResized = TRUE; LLPipeline::updateRenderDeferred(); - if (gUseWireframe) { gInitialDeferredModeForWireframe = LLPipeline::sRenderDeferred; @@ -1238,9 +1262,9 @@ class LLAdvancedToggleWireframe : public view_listener_t LLViewerShaderMgr::instance()->setShaders(); } - return true; +// return true; } -}; +//}; class LLAdvancedCheckWireframe : public view_listener_t { @@ -1973,6 +1997,15 @@ class LLAdvancedRebakeTextures : public view_listener_t }; +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 +void handle_refresh_attachments() +{ + if (isAgentAvatarValid()) + gAgentAvatarp->rebuildAttachments(); + LLAttachmentsMgr::instance().refreshAttachments(); +} +// [/SL:KB] + #if 1 //ndef LL_RELEASE_FOR_DOWNLOAD /////////////////////////// // DEBUG AVATAR TEXTURES // @@ -2632,6 +2665,15 @@ void handle_object_touch() LLPickInfo pick = LLToolPie::getInstance()->getPick(); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l + // NOTE: fallback code since we really shouldn't be getting an active selection if we can't touch this + if ( (RlvActions::isRlvEnabled()) && (!RlvActions::canTouch(object, pick.mObjectOffset)) ) + { + RLV_ASSERT(false); + return; + } +// [/RLVa:KB] + // *NOTE: Hope the packets arrive safely and in order or else // there will be some problems. // *TODO: Just fix this bad assumption. @@ -2679,6 +2721,14 @@ bool enable_object_touch(LLUICtrl* ctrl) new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch()); } +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g + if ( (RlvActions::isRlvEnabled()) && (new_value) ) + { + // RELEASE-RLVa: [RLVa-1.2.1] Make sure this stays in sync with handle_object_touch() + new_value = RlvActions::canTouch(obj, LLToolPie::getInstance()->getPick().mObjectOffset); + } +// [/RLVa:KB] + std::string item_name = ctrl->getName(); init_default_item_label(item_name); @@ -2711,7 +2761,11 @@ bool enable_object_touch(LLUICtrl* ctrl) void handle_object_open() { - LLFloaterReg::showInstance("openobject"); +// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e + if (enable_object_open()) + LLFloaterReg::showInstance("openobject"); +// [/RLVa:KB] +// LLFloaterReg::showInstance("openobject"); } bool enable_object_open() @@ -2941,7 +2995,17 @@ bool enable_object_edit() } else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) { - enable = true; +// enable = true; +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + bool fRlvCanEdit = (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDITOBJ)); + if (!fRlvCanEdit) + { + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsEditable f; + fRlvCanEdit = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == NULL); + } + enable = fRlvCanEdit; +// [/RLVa:KB] } return enable; @@ -2996,7 +3060,10 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getNumObjects() > 0) +// if (attachment->getNumObjects() > 0) +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) ) +// [/RLVa:KB] { new_value = true; break; @@ -3039,7 +3106,10 @@ bool enable_object_mute() bool is_linden = lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); bool is_self = avatar->isSelf(); - return !is_linden && !is_self; +// return !is_linden && !is_self; +// [RLVa:KB] - Checked: RLVa-1.2.1 + return !is_linden && !is_self && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())); +// [/RLVa:KB] } else { @@ -3088,11 +3158,20 @@ class LLAvatarCheckImpostorMode : public view_listener_t switch (mode) { case 0: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + return LLRenderMuteList::instance().getSavedVisualMuteSetting(avatar->getID()) == LLVOAvatar::AV_RENDER_NORMALLY; +// [/RLVa:KB] +// return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_RENDER_NORMALLY); case 1: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + return LLRenderMuteList::instance().getSavedVisualMuteSetting(avatar->getID()) == LLVOAvatar::AV_DO_NOT_RENDER; +// [/RLVa:KB] +// return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); case 2: - return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + return LLRenderMuteList::instance().getSavedVisualMuteSetting(avatar->getID()) == LLVOAvatar::AV_ALWAYS_RENDER; +// [/RLVa:KB] +// return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); default: return false; } @@ -3148,6 +3227,10 @@ class LLObjectMute : public view_listener_t avatar->mNeedsImpostorUpdate = TRUE; id = avatar->getID(); +// [RLVa:KB] - Checked: RLVa-1.0.0 + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, id)) + return true; +// [/RLVa:KB] LLNameValue *firstname = avatar->getNVPair("FirstName"); LLNameValue *lastname = avatar->getNVPair("LastName"); @@ -3300,7 +3383,10 @@ void handle_avatar_freeze(const LLSD& avatar_id) if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: RLVa-1.0.0 + args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotificationsUtil::add("FreezeAvatarFullname", args, payload, @@ -3429,7 +3515,10 @@ void handle_avatar_eject(const LLSD& avatar_id) if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: RLVa-1.0.0 + args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotificationsUtil::add("EjectAvatarFullname", args, payload, @@ -3449,7 +3538,10 @@ void handle_avatar_eject(const LLSD& avatar_id) if (!fullname.empty()) { LLSD args; - args["AVATAR_NAME"] = fullname; +// args["AVATAR_NAME"] = fullname; +// [RLVa:KB] - Checked: RLVa-1.0.0 + args["AVATAR_NAME"] = (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ? fullname : RlvStrings::getAnonym(fullname); +// [/RLVa:KB] LLNotificationsUtil::add("EjectAvatarFullnameNoBan", args, payload, @@ -3680,7 +3772,10 @@ class LLSelfStandUp : public view_listener_t bool enable_standup_self() { - return isAgentAvatarValid() && gAgentAvatarp->isSitting(); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + return isAgentAvatarValid() && gAgentAvatarp->isSitting() && RlvActions::canStand(); +// [/RLVa:KB] +// return isAgentAvatarValid() && gAgentAvatarp->isSitting(); } class LLSelfSitDown : public view_listener_t @@ -3701,7 +3796,10 @@ bool show_sitdown_self() bool enable_sitdown_self() { - return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); +// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying() && !gRlvHandler.hasBehaviour(RLV_BHVR_SIT); +// [/RLVa:KB] +// return show_sitdown_self() && !gAgentAvatarp->isEditingAppearance() && !gAgent.getFlying(); } class LLCheckPanelPeopleTab : public view_listener_t @@ -3945,7 +4043,10 @@ class LLAvatarEnableAddFriend : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); +// bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); +// [RLVa:KB] - Checked: RLVa-1.2.0 + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())); +// [/RLVa:KB] return new_value; } }; @@ -3979,7 +4080,10 @@ class LLEditEnableCustomizeAvatar : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gAgentWearables.areWearablesLoaded(); +// bool new_value = gAgentWearables.areWearablesLoaded(); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + bool new_value = gAgentWearables.areWearablesLoaded() && ((!rlv_handler_t::isEnabled()) || (RlvActions::canStand())); +// [/RLVa:KB] return new_value; } }; @@ -4011,6 +4115,16 @@ class LLEnableEditPhysics : public view_listener_t bool is_object_sittable() { +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.1.0j + // RELEASE-RLVa: [SL-2.2.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for + if (rlv_handler_t::isEnabled()) + { + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + if ( (pick.mObjectID.notNull()) && (!RlvActions::canSit(pick.getObject(), pick.mObjectOffset)) ) + return false; + } +// [/RLVa:KB] + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (object && object->getPCode() == LL_PCODE_VOLUME) @@ -4042,8 +4156,23 @@ void handle_object_sit_or_stand() // get object selection offset - if (object && object->getPCode() == LL_PCODE_VOLUME) +// if (object && object->getPCode() == LL_PCODE_VOLUME) +// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + if ( (object && object->getPCode() == LL_PCODE_VOLUME) && + ((!rlv_handler_t::isEnabled()) || (RlvActions::canSit(object, pick.mObjectOffset))) ) +// [/RLVa:KB] { +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) ) + { + if (gAgentAvatarp->isSitting()) + { + gAgent.standUp(); + return; + } + gRlvHandler.setSitSource(gAgent.getPositionGlobal()); + } +// [/RLVa:KB] gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); gMessageSystem->nextBlockFast(_PREHASH_AgentData); @@ -4071,6 +4200,11 @@ class LLLandSit : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if ( (rlv_handler_t::isEnabled()) && ((!RlvActions::canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + return true; +// [/RLVa:KB] + gAgent.standUp(); LLViewerParcelMgr::getInstance()->deselectLand(); @@ -4110,6 +4244,13 @@ void handle_reset_view() gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); reset_view_final( TRUE ); LLFloaterCamera::resetCameraMode(); + +// [SL:KB] - Patch: Appearance-RefreshAttachments | Checked: Catznip-5.3 + if (isAgentAvatarValid()) + { + gAgentAvatarp->rebuildAttachments(); + } +// [/SL:KB] } class LLViewResetView : public view_listener_t @@ -4594,6 +4735,17 @@ void handle_take_copy() { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; +// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) + { + // Allow only if the avie isn't sitting on any of the selected objects + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectIsSittingOn f(gAgentAvatarp); + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) ) + return; + } +// [/RLVa:KB] + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } @@ -4608,7 +4760,10 @@ class LLObjectReturn : public view_listener_t bool handleEvent(const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; - +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.4.0a) | Modified: RLVa-1.0.0b + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) return true; +// [/RLVa:KB] + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. @@ -4655,6 +4810,12 @@ class LLObjectEnableReturn : public view_listener_t // Do not enable if nothing selected return false; } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a + if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) + { + return false; + } +// [/RLVa:KB] #ifdef HACKED_GODLIKE_VIEWER bool new_value = true; #else @@ -4683,11 +4844,14 @@ void handle_take() { // we want to use the folder this was derezzed from if it's // available. Otherwise, derez to the normal place. - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) +// if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + if ( (LLSelectMgr::getInstance()->getSelection()->isEmpty()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { return; } - + BOOL you_own_everything = TRUE; BOOL locked_but_takeable_object = FALSE; LLUUID category_id; @@ -4836,7 +5000,10 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect // one item selected can be copied to inventory. BOOL enable_take() { - if (sitting_on_selection()) +// if (sitting_on_selection()) +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b + if ( (sitting_on_selection()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) ) +// [/RLVa:KB] { return FALSE; } @@ -5381,8 +5548,12 @@ class LLToolsReleaseKeys : public view_listener_t { bool handleEvent(const LLSD& userdata) { - gAgent.forceReleaseControls(); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + return true; +// [/RLVa:KB] + gAgent.forceReleaseControls(); return true; } }; @@ -5391,7 +5562,11 @@ class LLToolsEnableReleaseKeys : public view_listener_t { bool handleEvent(const LLSD& userdata) { - return gAgent.anyControlGrabbed(); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a + return (gAgent.anyControlGrabbed()) && + ( (!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ); +// [/RLVa:KB] +// return gAgent.anyControlGrabbed(); } }; @@ -5788,6 +5963,11 @@ void show_debug_menus() gMenuBarView->setItemVisible("Advanced", debug); // gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + +// [RLVa:KB] - Checked: 2011-08-16 (RLVa-1.4.0b) | Modified: RLVa-1.4.0b + // NOTE: this is supposed to execute whether RLVa is enabled or not + rlvMenuToggleVisible(); +// [/RLVa:KB] gMenuBarView->setItemVisible("Debug", qamode); gMenuBarView->setItemEnabled("Debug", qamode); @@ -5903,16 +6083,16 @@ class LLWorldAlwaysRun : public view_listener_t if (gAgent.getAlwaysRun()) { gAgent.clearAlwaysRun(); - gAgent.clearRunning(); +// gAgent.clearRunning(); } else { gAgent.setAlwaysRun(); - gAgent.setRunning(); +// gAgent.setRunning(); } // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); +// gAgent.sendWalkRun(gAgent.getAlwaysRun()); // Update Movement Controls according to AlwaysRun mode LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); @@ -5967,6 +6147,11 @@ class LLWorldCreateLandmark : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.0.0 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return true; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark")); return true; @@ -5977,12 +6162,24 @@ class LLWorldPlaceProfile : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + return true; +// [/RLVa:KB] + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); return true; } }; +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 +bool enable_place_profile() +{ + return LLFloaterSidePanelContainer::canShowPanel("places", LLSD().with("type", "agent")); +} +// [/RLVa:KB] + void handle_look_at_selection(const LLSD& param) { const F32 PADDING_FACTOR = 1.75f; @@ -6052,7 +6249,10 @@ class LLAvatarInviteToGroup : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { LLAvatarActions::inviteToGroup(avatar->getID()); } @@ -6065,7 +6265,10 @@ class LLAvatarAddFriend : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !LLAvatarActions::isFriend(avatar->getID())) +// if(avatar && !LLAvatarActions::isFriend(avatar->getID())) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { request_friendship(avatar->getID()); } @@ -6113,6 +6316,9 @@ class LLAvatarResetSkeleton: public view_listener_t if(avatar) { avatar->resetSkeleton(false); +// [SL:KB] - Patch: Appearance-RefreshAttachments | Checked: Catznip-5.3 + avatar->rebuildAttachments(); +// [/SL:KB] } return true; } @@ -6140,6 +6346,9 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t if (avatar) { avatar->resetSkeleton(true); +// [SL:KB] - Patch: Appearance-RefreshAttachments | Checked: Catznip-5.3 + avatar->rebuildAttachments(); +// [/SL:KB] } return true; } @@ -6150,7 +6359,10 @@ class LLAvatarAddContact : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { create_inventory_callingcard(avatar->getID()); } @@ -6214,7 +6426,10 @@ bool enable_pay_avatar() { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar* avatar = find_avatar_from_object(obj); - return (avatar != NULL); +// return (avatar != NULL); +// [RLVa:KB] - Checked: RLVa-1.2.1 + return (avatar != NULL) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())); +// [/RLVa:KB] } bool enable_pay_object() @@ -6234,7 +6449,10 @@ bool enable_pay_object() bool enable_object_stand_up() { // 'Object Stand Up' menu item is enabled when agent is sitting on selection - return sitting_on_selection(); +// return sitting_on_selection(); +// [RLVa:KB] - Checked: 2010-07-24 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + return sitting_on_selection() && ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) ); +// [/RLVa:KB] } bool enable_object_sit(LLUICtrl* ctrl) @@ -6259,6 +6477,17 @@ bool enable_object_sit(LLUICtrl* ctrl) gMenuHolder->childSetValue(item_name, get_default_item_label(item_name)); } } + +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + // RELEASE-RLVA: [SL-2.2.0] Make this match what happens in handle_object_sit_or_stand() + if (rlv_handler_t::isEnabled()) + { + const LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + if (pick.mObjectID.notNull()) + sitting_on_sel = !RlvActions::canSit(pick.getObject(), pick.mObjectOffset); + } +// [/RLVa:KB] + return !sitting_on_sel && is_object_sittable(); } @@ -6513,7 +6742,10 @@ class LLShowAgentProfile : public view_listener_t } LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) +// if (avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && ((RlvActions::canShowName(RlvActions::SNC_DEFAULT, agent_id)) || (gAgent.getID() == agent_id)) ) +// [/RLVa:KB] { LLAvatarActions::showProfile(avatar->getID()); } @@ -6662,6 +6894,19 @@ class LLObjectAttachToAvatar : public view_listener_t LLViewerJointAttachment* attachment_point = NULL; if (index > 0) attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + // RELEASE-RLVa: [SL-2.2.0] If 'index != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()] + if ( (rlv_handler_t::isEnabled()) && + ( ((!index) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) || // Can't wear on default + ((index) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(attachment_point)) == 0)) || // or non-attachable attachpt + (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) ) // Attach on object == "Take" + { + setObjectSelection(NULL); // Clear the selection or it'll get stuck + return true; + } +// [/RLVa:KB] + confirmReplaceAttachment(0, attachment_point); } return true; @@ -6806,6 +7051,24 @@ class LLAttachmentDrop : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5 + if (rlv_handler_t::isEnabled()) + { + if (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) + { + // NOTE: copy/paste of the code in enable_detach() + LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return true; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) + { + return true; + } + } +// [/RLVa:KB] + LLSD payload; LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -6831,14 +7094,21 @@ class LLAttachmentDetachFromPoint : public view_listener_t { uuid_vec_t ids_to_remove; const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment->getNumObjects() > 0) +// if (attachment->getNumObjects() > 0) +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) ) +// [/RLVa:KB] { for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); iter != attachment->mAttachedObjects.end(); iter++) { LLViewerObject *attached_object = iter->get(); +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(attached_object)) ) + continue; ids_to_remove.push_back(attached_object->getAttachmentItemID()); +// [/RLVa:KB] } } if (!ids_to_remove.empty()) @@ -6851,6 +7121,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + // RELEASE-RLVa: [SL-2.2.0] When attaching to a specific point the object will be "add attached" [see LLSelectMgr::sendAttach()] + bool fRlvEnable = true; +// [/RLVa:KB] std::string label; LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); if (menu) @@ -6875,9 +7149,18 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) } } } + +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if (rlv_handler_t::isEnabled()) + fRlvEnable = (!gRlvAttachmentLocks.isLockedAttachmentPoint(attachment, RLV_LOCK_ADD)); +// [/RLVa:KB] + menu->setLabel(label); } - return true; +// return true; +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + return fRlvEnable; +// [/RLVa:KB] } class LLAttachmentDetach : public view_listener_t @@ -6916,6 +7199,17 @@ class LLAttachmentDetach : public view_listener_t return true; } +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 + // NOTE: copy/paste of the code in enable_detach() + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return true; + } +// [/RLVa:KB] + LLAppearanceMgr::instance().removeItemFromAvatar(object->getAttachmentItemID()); return true; @@ -6992,7 +7286,10 @@ class LLAttachmentEnableDrop : public view_listener_t } //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach() && can_build && item; +// bool new_value = enable_detach() && can_build && item; +// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b + bool new_value = enable_detach() && can_build && item && (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)); +// [/RLVa:KB] return new_value; } @@ -7017,6 +7314,20 @@ BOOL enable_detach(const LLSD&) // ...if it's you, good to detach if (avatar->getID() == gAgent.getID()) { +// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5 + // NOTE: this code is reused as-is in LLAttachmentDetach::handleEvent() and LLAttachmentDrop::handleEvent() + // so any changes here should be reflected there as well + + // RELEASE-RLVa: [SL-2.2.0] LLSelectMgr::sendDetach() and LLSelectMgr::sendDropAttachment() call sendListToRegions with + // SEND_ONLY_ROOTS so we only need to examine the roots which saves us time + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + return FALSE; + } +// [/RLVa:KB] return TRUE; } @@ -7036,8 +7347,33 @@ class LLAttachmentEnableDetach : public view_listener_t }; // Used to tell if the selected object can be attached to your avatar. -BOOL object_selected_and_point_valid() +//BOOL object_selected_and_point_valid() +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +BOOL object_selected_and_point_valid(const LLSD& sdParam) +// [/RLVa:KB] { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + if (rlv_handler_t::isEnabled()) + { + if (!isAgentAvatarValid()) + return FALSE; + + // RELEASE-RLVa: [SL-2.2.0] Look at the caller graph for this function on every new release + // - object_is_wearable() => dead code [sdParam == 0 => default attach point => OK!] + // - enabler set up in LLVOAvatarSelf::buildMenus() => Rezzed prim / Put On / "Attach To" [sdParam == idxAttachPt] + // - "Object.EnableWear" enable => Rezzed prim / Put On / "Wear" or "Add" [sdParam blank] + // RELEASE-RLVa: [SL-2.2.0] If 'idxAttachPt != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()] + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, sdParam.asInteger(), (LLViewerJointAttachment*)NULL); + if ( ((!pAttachPt) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) || // Can't wear on default attach point + ((pAttachPt) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(pAttachPt)) == 0)) || // or non-attachable attach point + (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) // Attach on object == "Take" + { + return FALSE; + } + } +// [/RLVa:KB] + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); for (LLObjectSelection::root_iterator iter = selection->root_begin(); iter != selection->root_end(); iter++) @@ -7065,14 +7401,17 @@ BOOL object_selected_and_point_valid() (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); } - BOOL object_is_wearable() { if (!isAgentAvatarValid()) + if (!object_selected_and_point_valid(LLSD(0))) { return FALSE; } - if (!object_selected_and_point_valid()) +// if (!object_selected_and_point_valid()) +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + if (!object_selected_and_point_valid(LLSD(0))) +// [/RLVa:KB] { return FALSE; } @@ -7083,7 +7422,6 @@ BOOL object_is_wearable() return gAgentAvatarp->canAttachMoreObjects(); } - class LLAttachmentPointFilled : public view_listener_t { bool handleEvent(const LLSD& user_data) @@ -7092,7 +7430,12 @@ class LLAttachmentPointFilled : public view_listener_t LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); if (found_it != gAgentAvatarp->mAttachmentPoints.end()) { - enable = found_it->second->getNumObjects() > 0; +// enable = found_it->second->getNumObjects() > 0; +// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // Enable the option if there is at least one attachment on this attachment point that can be detached + enable = (found_it->second->getNumObjects() > 0) && + ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(found_it->second))); +// [/RLVa:KB] } return enable; } @@ -7103,7 +7446,10 @@ class LLAvatarSendIM : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { LLAvatarActions::startIM(avatar->getID()); } @@ -7116,7 +7462,10 @@ class LLAvatarCall : public view_listener_t bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) +// if(avatar) +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (avatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar->getID())) ) +// [/RLVa:KB] { LLAvatarActions::startCall(avatar->getID()); } @@ -7124,6 +7473,19 @@ class LLAvatarCall : public view_listener_t } }; +// [RLVa:KB] - Checked: RLVa-1.2.1 +bool enable_avatar_call() +{ + if (RlvActions::isRlvEnabled()) + { + const LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if ((!pAvatar) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, pAvatar->getID()))) + return false; + } + return LLAvatarActions::canCall(); +} +// [/RLVa:KB] + namespace { struct QueueObjects : public LLSelectedNodeFunctor @@ -7191,6 +7553,17 @@ class LLToolsSelectedScriptAction : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a + // We'll allow resetting the scripts of objects on a non-attachable attach point since they wouldn't be able to circumvent anything + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + RlvSelectHasLockedAttach f; + if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != NULL) ) + return true; + } +// [/RLVa:KB] + std::string action = userdata.asString(); bool mono = false; std::string msg, name; @@ -7334,12 +7707,30 @@ void handle_selected_material_info() void handle_test_male(void*) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + // TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this? + if ( (rlv_handler_t::isEnabled()) && + ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) ) + { + return; + } +// [/RLVa:KB] + LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); //gGestureList.requestResetFromServer( TRUE ); } void handle_test_female(void*) { +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + // TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this? + if ( (rlv_handler_t::isEnabled()) && + ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) ) + { + return; + } +// [/RLVa:KB] + LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); //gGestureList.requestResetFromServer( FALSE ); } @@ -7508,6 +7899,22 @@ class LLSomethingSelectedNoHUD : public view_listener_t static bool is_editable_selected() { +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a + // RELEASE-RLVa: [SL-2.2.0] Check that this still isn't called by anything but script actions in the Build menu + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) + { + LLObjectSelectionHandle hSelection = LLSelectMgr::getInstance()->getSelection(); + + // NOTE: this is called for 5 different menu items so we'll trade accuracy for efficiency and only + // examine root nodes (LLToolsSelectedScriptAction::handleEvent() will catch what we miss) + RlvSelectHasLockedAttach f; + if ( (hSelection->isAttachment()) && (hSelection->getFirstRootNode(&f)) ) + { + return false; + } + } +// [/RLVa:KB] + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); } @@ -7552,7 +7959,11 @@ bool enable_object_take_copy() { virtual bool apply(LLViewerObject* obj) { - return (!obj->permCopy() || obj->isAttachment()); +// return (!obj->permCopy() || obj->isAttachment()); +// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g + return (!obj->permCopy() || obj->isAttachment()) || + ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->getRoot() == obj) ); +// [/RLVa:KB] } } func; const bool firstonly = true; @@ -7657,7 +8068,10 @@ class LLWorldEnableCreateLandmark : public view_listener_t { bool handleEvent(const LLSD& userdata) { - return !LLLandmarkActions::landmarkAlreadyExists(); +// return !LLLandmarkActions::landmarkAlreadyExists(); +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.2.1 + return (!LLLandmarkActions::landmarkAlreadyExists()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] } }; @@ -7678,6 +8092,10 @@ class LLWorldEnableTeleportHome : public view_listener_t LLViewerRegion* regionp = gAgent.getRegion(); bool agent_on_prelude = (regionp && regionp->isPrelude()); bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + enable_teleport_home &= + (!rlv_handler_t::isEnabled()) || ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC))); +// [/RLVa:KB] return enable_teleport_home; } }; @@ -8127,6 +8545,9 @@ void handle_rebake_textures(void*) gAgentAvatarp->forceBakeAllTextures(slam_for_debug); if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) { +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-06-27 (Catznip-3.7) +// LLAppearanceMgr::instance().syncCofVersionAndRefresh(); +// [/SL:KB] LLAppearanceMgr::instance().requestServerAppearanceUpdate(); } } @@ -8167,7 +8588,10 @@ class LLViewHighlightTransparent : public view_listener_t { bool handleEvent(const LLSD& userdata) { - LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; +// LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + LLDrawPoolAlpha::sShowDebugAlpha = (!LLDrawPoolAlpha::sShowDebugAlpha) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)); +// [/RLVa:KB] return true; } }; @@ -8379,6 +8803,11 @@ class LLViewShowHUDAttachments : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c + if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) ) + return true; +// [/RLVa:KB] + LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; return true; } @@ -8399,8 +8828,15 @@ class LLEditEnableTakeOff : public view_listener_t { std::string clothing = userdata.asString(); LLWearableType::EType type = LLWearableType::typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) +// if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) +// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a + // NOTE: see below - enable if there is at least one wearable on this type that can be removed + if ( (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) && + ((!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(type))) ) +// [/RLVa:KB] + { return LLAgentWearables::selfHasWearable(type); + } return false; } }; @@ -8421,6 +8857,22 @@ class LLEditTakeOff : public view_listener_t { // MULTI-WEARABLES: assuming user wanted to remove top shirt. U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; + +// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearable(type)) ) + { + // We'll use the first wearable we come across that can be removed (moving from top to bottom) + for (; wearable_index >= 0; wearable_index--) + { + const LLViewerWearable* pWearable = gAgentWearables.getViewerWearable(type, wearable_index); + if (!gRlvWearableLocks.isLockedWearable(pWearable)) + break; + } + if (wearable_index < 0) + return true; // No wearable found that can be removed + } +// [/RLVa:KB] + LLUUID item_id = gAgentWearables.getWearableItemID(type,wearable_index); LLAppearanceMgr::instance().removeItemFromAvatar(item_id); } @@ -8473,6 +8925,11 @@ class LLWorldEnvSettings : public view_listener_t { bool handleEvent(const LLSD& userdata) { +// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g + if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + return true; +// [/RLVa:KB] + std::string tod = userdata.asString(); if (tod == "editor") @@ -8741,6 +9198,9 @@ void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y) { landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); } +// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 + landmark_item->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] if(gMenuHolder->hasVisibleMenu()) { @@ -8896,6 +9356,9 @@ void initialize_menus() view_listener_t::addMenu(new LLWorldSetDoNotDisturb(), "World.SetDoNotDisturb"); view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); +// [RLVa:KB] + enable.add("World.EnablePlaceProfile", boost::bind(&enable_place_profile)); +// [/RLVa:KB] view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); @@ -9073,6 +9536,9 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); +// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0 + commit.add("Advanced.RefreshAttachments", boost::bind(&handle_refresh_attachments)); +// [/SL:KB] view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); // Advanced > Network @@ -9163,7 +9629,10 @@ void initialize_menus() commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); - enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); +// enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b + enable.add("Avatar.EnableCall", boost::bind(&enable_avatar_call)); +// [/RLVa:KB] view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); @@ -9270,4 +9739,13 @@ void initialize_menus() view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); + +// [RLVa:KB] - Checked: RLVa-2.0.0 + enable.add("RLV.MainToggleVisible", boost::bind(&rlvMenuMainToggleVisible, _1)); + if (RlvActions::isRlvEnabled()) + { + enable.add("RLV.CanShowName", boost::bind(&rlvMenuCanShowName)); + enable.add("RLV.EnableIfNot", boost::bind(&rlvMenuEnableIfNot, _2)); + } +// [/RLVa:KB] } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 68824054073894068e961be95a6709f11afc11d0..8dc6c3634b8ea134bb4e8405cd094e15fd3385c6 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -38,6 +38,10 @@ class LLParcelSelection; class LLObjectSelection; class LLSelectNode; +// [RLVa:KB] - Checked: RLVa-2.0.0 +void set_use_wireframe(bool useWireframe); +// [/RLVa:KB] + void initialize_edit_menu(); void initialize_spellcheck_menu(); void init_menus(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3dd2f402fee9e8e632b22f4671ee3357a80f5d5a..8a266777286eafb32b23e78dceed3ab6f80775e8 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -115,6 +115,12 @@ #include "llpanelplaceprofile.h" #include "llviewerregion.h" #include "llfloaterregionrestarting.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvinventory.h" +#include "rlvui.h" +// [/RLVa:KB] #include <boost/algorithm/string/split.hpp> // #include <boost/foreach.hpp> @@ -355,7 +361,18 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) // modified_form->setElementEnabled("Accept", false); // modified_form->setElementEnabled("Decline", false); // notification_ptr->updateForm(modified_form); - // notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell +// /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); +// /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; +// if ( (!pToast) || (!pToast->getCanBeStored()) ) +// { +// [/SL:KB] +// notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// } +// [/SL:KB] + } return false; @@ -1681,7 +1698,14 @@ void LLOfferInfo::sendReceiveResponse(bool accept, const LLUUID &destination_fol if(IM_INVENTORY_OFFERED == mIM) { // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); +// LLRecentPeople::instance().add(mFromID); +// [RLVa:KB] - Checked: RLVa-2.0.1 + // RELEASE-RLVa: [RLVa-2.0.1] Make sure this stays in sync with the condition in inventory_offer_handler() + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mFromID)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)) || (RlvUIEnabler::hasOpenProfile(mFromID)); + if (fRlvCanShowName) + LLRecentPeople::instance().add(mFromID); +// [/RLVa:KB] } if (mTransactionID.isNull()) @@ -1822,6 +1846,18 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // This is an offer from an agent. In this case, the back // end has already copied the items into your inventory, // so we can fetch it out of our inventory. +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0) + if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) + { + RlvGiveToRLVAgentOffer* pOfferObserver = new RlvGiveToRLVAgentOffer(mObjectID); + pOfferObserver->startFetch(); + if (pOfferObserver->isFinished()) + pOfferObserver->done(); + else + gInventory.addObserver(pOfferObserver); + } +// [/RLVa:KB] + if (gSavedSettings.getBOOL("ShowOfferedInventory")) { LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); @@ -2008,6 +2044,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const } else { +/* LLAvatarName av_name; if (LLAvatarNameCache::get(mFromID, &av_name)) { @@ -2021,6 +2058,22 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); } +*/ +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + std::string name_slurl = LLSLURL("agent", mFromID, "about").getSLURLString(); + +// [RLVa:KB] - Checked: RLVa-2.0.1 + // RELEASE-RLVa: [RLVa-2.0.1] Make sure this stays in sync with the condition in inventory_offer_handler() + bool fRlvCanShowName = (!RlvActions::isRlvEnabled()) || + (RlvActions::canShowName(RlvActions::SNC_DEFAULT, mFromID)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)) || (RlvUIEnabler::hasOpenProfile(mFromID)); + if (!fRlvCanShowName) + name_slurl = LLSLURL("agent", mFromID, "rlvanonym").getSLURLString(); +// [/RLVa:KB] + + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName + + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + name_slurl; + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + name_slurl; +// [/SL:KB] } } else @@ -2035,6 +2088,34 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const switch(button) { case IOR_ACCEPT: +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) + // Only treat the offer as 'Give to #RLV' if: + // - the user has enabled the feature + // - the inventory offer came from a script (and specifies a folder) + // - the name starts with the prefix - mDesc format: '[OBJECTNAME]' ( http://slurl.com/... ) + if ( (rlv_handler_t::isEnabled()) && (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + { + if (!RlvSettings::getForbidGiveToRLV()) + { + const LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID(); + if (idRlvRoot.notNull()) + mFolderID = idRlvRoot; + + // "accepted_in_rlv" is sent from RlvGiveToRLVTaskOffer *after* we have the folder + RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID); + gInventory.addObserver(pOfferObserver); + } + else + { + std::string::size_type idxToken = mDesc.find("' ( http://"); + if (std::string::npos != idxToken) + { + RlvBehaviourNotifyHandler::sendNotification("accepted_in_inv inv_offer " + mDesc.substr(1, idxToken - 1)); + } + } + } +// [/RLVa:KB] + destination = mFolderID; //don't spam user if flooded if (check_offer_throttle(mFromName, true)) @@ -2058,6 +2139,17 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const // but user can mute object after receiving message accept = false; } + +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e + if ( (rlv_handler_t::isEnabled()) && + (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + { + std::string::size_type idxToken = mDesc.find("' ( http://"); + if (std::string::npos != idxToken) + RlvBehaviourNotifyHandler::sendNotification("declined inv_offer " + mDesc.substr(1, idxToken - 1)); + } +// [/RLVa:KB] + break; } @@ -2139,7 +2231,18 @@ bool lure_callback(const LLSD& notification, const LLSD& response) modified_form->setElementEnabled("Teleport", false); modified_form->setElementEnabled("Cancel", false); notification_ptr->updateForm(modified_form); - notification_ptr->repost(); + +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell + /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); + /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; + if ( (!pToast) || (!pToast->getCanBeStored()) ) + { +// [/SL:KB] + notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) + } +// [/SL:KB] } return false; @@ -2501,9 +2604,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mPosAgent = chatter->getPositionAgent(); // Make swirly things only for talking objects. (not script debug messages, though) - if (chat.mSourceType == CHAT_SOURCE_OBJECT - && chat.mChatType != CHAT_TYPE_DEBUG_MSG - && gSavedSettings.getBOOL("EffectScriptChatParticles") ) +// if (chat.mSourceType == CHAT_SOURCE_OBJECT +// && chat.mChatType != CHAT_TYPE_DEBUG_MSG +// && gSavedSettings.getBOOL("EffectScriptChatParticles") ) +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g + if ( ((chat.mSourceType == CHAT_SOURCE_OBJECT) && (chat.mChatType != CHAT_TYPE_DEBUG_MSG)) && + (gSavedSettings.getBOOL("EffectScriptChatParticles")) && + ((!rlv_handler_t::isEnabled()) || (CHAT_TYPE_OWNER != chat.mChatType)) ) +// [/RLVa:KB] { LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); psc->setSourceObject(chatter); @@ -2533,6 +2641,75 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) color.setVec(1.f,1.f,1.f,1.f); msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); +// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f + if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) ) + { + // NOTE: chatter can be NULL (may not have rezzed yet, or could be another avie's HUD attachment) + BOOL is_attachment = (chatter) ? chatter->isAttachment() : FALSE; + BOOL is_owned_by_me = (chatter) ? chatter->permYouOwner() : FALSE; + + // Filtering "rules": + // avatar => filter all avie text (unless it's this avie or they're an exemption) + // objects => filter everything except attachments this avie owns (never filter llOwnerSay or llRegionSayTo chat) + if ( ( (CHAT_SOURCE_AGENT == chat.mSourceType) && (from_id != gAgent.getID()) ) || + ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) && + (CHAT_TYPE_OWNER != chat.mChatType) && (CHAT_TYPE_DIRECT != chat.mChatType) ) ) + { + bool fIsEmote = RlvUtil::isEmote(mesg); + if ((!fIsEmote) && + (((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id))) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHATFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVCHATFROM, from_id))) )) + { + if ( (gRlvHandler.filterChat(mesg, false)) && (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) ) + return; + } + else if ((fIsEmote) && + (((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTE)) && (!gRlvHandler.isException(RLV_BHVR_RECVEMOTE, from_id))) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTEFROM)) && (gRlvHandler.isException(RLV_BHVR_RECVEMOTEFROM, from_id))) )) + { + if (!gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) + return; + mesg = "/me ..."; + } + } + + // Filtering "rules": + // avatar => filter only their name (unless it's this avie) + // other => filter everything + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + { + if (CHAT_SOURCE_AGENT != chat.mSourceType) + { + RlvUtil::filterNames(chat.mFromName); + } + else if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, chat.mFromID)) + { + chat.mFromName = RlvStrings::getAnonym(chat.mFromName); + chat.mRlvNamesFiltered = TRUE; + } + } + + // Create an "objectim" URL for objects if we're either @shownames or @showloc restricted + // (we need to do this now because we won't be have enough information to do it later on) + if ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && + ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) || (!RlvActions::canShowLocation()) ) ) + { + LLSD sdQuery; + sdQuery["name"] = chat.mFromName; + sdQuery["owner"] = owner_id; + + if ( (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, owner_id)) && (!is_owned_by_me) ) + sdQuery["rlv_shownames"] = true; + + const LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); + if (pRegion) + sdQuery["slurl"] = LLSLURL(pRegion->getName(), chat.mPosAgent).getLocationString(); + + chat.mURL = LLSLURL("objectim", from_id, LLURI::mapToQueryString(sdQuery)).getSLURLString(); + } + } +// [/RLVa:KB] + BOOL ircstyle = FALSE; // Look for IRC-style emotes here so chatbubbles work @@ -2583,8 +2760,100 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) case CHAT_TYPE_WHISPER: chat.mText = LLTrans::getString("whisper") + " "; break; - case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: +// [RLVa:KB] - Checked: 2010-02-XX (RLVa-1.2.0a) | Modified: RLVa-1.1.0f + // TODO-RLVa: [RLVa-1.2.0] consider rewriting this before a RLVa-1.2.0 release + if ( (rlv_handler_t::isEnabled()) && (mesg.length() > 3) && (RLV_CMD_PREFIX == mesg[0]) && (CHAT_TYPE_OWNER == chat.mChatType) && + ((!chatter) || (!chatter->isAttachment()) || (!chatter->isTempAttachment()) || (RlvSettings::getEnableTemporaryAttachments())) ) + { + mesg.erase(0, 1); + LLStringUtil::toLower(mesg); + + std::string strExecuted, strFailed, strRetained, *pstr; + + boost_tokenizer tokens(mesg, boost::char_separator<char>(",", "", boost::drop_empty_tokens)); + for (boost_tokenizer::iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + { + std::string strCmd = *itToken; + + ERlvCmdRet eRet = gRlvHandler.processCommand(from_id, strCmd, true); + if ( (RlvSettings::getDebug()) && + ( (!RlvSettings::getDebugHideUnsetDup()) || + ((RLV_RET_SUCCESS_UNSET != eRet) && (RLV_RET_SUCCESS_DUPLICATE != eRet)) ) ) + { + if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) ) + pstr = &strExecuted; + else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) ) + pstr = &strFailed; + else if (RLV_RET_RETAINED == eRet) + pstr = &strRetained; + else + { + RLV_ASSERT(false); + pstr = &strFailed; + } + + const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet); + if (pstrSuffix) + strCmd.append(" (").append(pstrSuffix).append(")"); + + if (!pstr->empty()) + pstr->push_back(','); + pstr->append(strCmd); + } + } + + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + if ( (!RlvSettings::getDebug()) || ((strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty())) ) + return; + + // Silly people want comprehensive debug messages, blah :p + if ( (!strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty()) ) + { + chat.mText = " executes: @"; + mesg = strExecuted; + } + else if ( (strExecuted.empty()) && (!strFailed.empty()) && (strRetained.empty()) ) + { + chat.mText = " failed: @"; + mesg = strFailed; + } + else if ( (strExecuted.empty()) && (strFailed.empty()) && (!strRetained.empty()) ) + { + chat.mText = " retained: @"; + mesg = strRetained; + } + else + { + chat.mText = ": @"; + if (!strExecuted.empty()) + mesg += "\n - executed: @" + strExecuted; + if (!strFailed.empty()) + mesg += "\n - failed: @" + strFailed; + if (!strRetained.empty()) + mesg += "\n - retained: @" + strRetained; + } + + break; + } +// [/RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g + // Copy/paste from above + if ( (rlv_handler_t::isEnabled()) && (chatter) && (chat.mSourceType == CHAT_SOURCE_OBJECT) && + (gSavedSettings.getBOOL("EffectScriptChatParticles")) ) + { + LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); + psc->setSourceObject(chatter); + psc->setColor(color); + //We set the particles to be owned by the object's owner, + //just in case they should be muted by the mute list + psc->setOwnerUUID(owner_id); + LLViewerPartSim::getInstance()->addPartSource(psc); + } +// [/RLVa:KB] + case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_NORMAL: case CHAT_TYPE_DIRECT: break; @@ -2709,7 +2978,10 @@ void process_teleport_start(LLMessageSystem *msg, void**) // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM LLViewerMessage::getInstance()->mTeleportStartedSignal(); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) ) +// [/RLVa:KB] { gViewerWindow->setProgressCancelButtonVisible(FALSE); } @@ -2751,7 +3023,10 @@ void process_teleport_progress(LLMessageSystem* msg, void**) } U32 teleport_flags = 0x0; msg->getU32("Info", "TeleportFlags", teleport_flags); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b + if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) ) +// [/RLVa:KB] { gViewerWindow->setProgressCancelButtonVisible(FALSE); } @@ -3188,7 +3463,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } // send walk-vs-run status - gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); +// gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + gAgent.sendWalkRun(); +// [/RLVa:KB] // If the server version has changed, display an info box and offer // to display the release notes, unless this is the initial log in. @@ -3721,6 +3999,15 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) LLViewerObject *objectp = gObjectList.findObject(id); if (objectp) { +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + if ( (objectp->isAttachment()) && (!objectp->isTempAttachment()) && (LLAgent::TELEPORT_NONE != gAgent.getTeleportState()) && + (gAgentAvatarp) && (objectp->permYouOwner()) && (gSavedSettings.getBOOL("BlockAttachmentKillsOnTeleport")) ) + { + //gAgentAvatarp->addPendingDetach(objectp->getRootEdit()->getID()); + continue; + } +// [/SL:KB] + // Display green bubble on kill if ( gShowObjectUpdates ) { @@ -5306,6 +5593,15 @@ void process_alert_core(const std::string& message, BOOL modal) } std::string new_msg =LLNotifications::instance().getGlobalString(text); +// [RLVa:KB] - Checked: RLVa-1.4.5 + if ( (new_msg == text) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(new_msg); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + RlvUtil::filterNames(new_msg); + } +// [/RLVa:KB] args["MESSAGE"] = new_msg; LLNotificationsUtil::add("SystemMessage", args); } @@ -5313,6 +5609,15 @@ void process_alert_core(const std::string& message, BOOL modal) { LLSD args; std::string new_msg =LLNotifications::instance().getGlobalString(message); +// [RLVa:KB] - Checked: RLVa-1.4.5 + if ( (new_msg == message) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(new_msg); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + RlvUtil::filterNames(new_msg); + } +// [/RLVa:KB] args["ERROR_MESSAGE"] = new_msg; LLNotificationsUtil::add("ErrorMessage", args); } @@ -5328,6 +5633,16 @@ void process_alert_core(const std::string& message, BOOL modal) std::string localized_msg; bool is_message_localized = LLTrans::findString(localized_msg, new_msg); +// [RLVa:KB] - Checked: RLVa-1.4.5 + if ( (new_msg == message) && (RlvActions::isRlvEnabled()) ) + { + if (!RlvActions::canShowLocation()) + RlvUtil::filterLocation(new_msg); + if (!RlvActions::canShowName(RlvActions::SNC_DEFAULT)) + RlvUtil::filterNames(new_msg); + } +// [/RLVa:KB] + args["MESSAGE"] = is_message_localized ? localized_msg : new_msg; LLNotificationsUtil::add("SystemMessageTip", args); } @@ -5488,7 +5803,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp if (viewregion) { // got the region, so include the region and 3d coordinates of the object - notice.setArg("[REGIONNAME]", viewregion->getName()); + notice.setArg("[REGIONNAME]", viewregion->getName()); std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); notice.setArg("[REGIONPOS]", formatpos); @@ -5496,7 +5811,15 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp } } - if (!foundpos) +// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.0.0a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + notice.setArg("[REGIONNAME]", RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); + notice.setArg("[REGIONPOS]", RlvStrings::getString(RLV_STRING_HIDDEN)); + } + else if (!foundpos) +// [/RLVa:KB] +// if (!foundpos) { // unable to determine location of the object notice.setArg("[REGIONNAME]", "(unknown region)"); @@ -5510,8 +5833,12 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp std::string perms; BOOST_FOREACH(script_perm_t script_perm, SCRIPT_PERMISSIONS) { - if ((orig_questions & script_perm.permbit) - && script_perm.caution) +// if ((orig_questions & script_perm.permbit) +// && script_perm.caution) +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (orig_questions & script_perm.permbit) && + ((script_perm.caution) || (notification["payload"]["rlv_notify"].asBoolean())) ) +// [/RLVa:KB] { count++; caution = TRUE; @@ -5531,11 +5858,25 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp // log a chat message as long as at least one requested permission // is a caution permission +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) if (caution) { - LLChat chat(notice.getString()); - // LLFloaterChat::addChat(chat, FALSE, FALSE); + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if(nearby_chat) + { + LLChat chat_msg(notice.getString()); + chat_msg.mFromName = SYSTEM_FROM; + chat_msg.mFromID = LLUUID::null; + chat_msg.mSourceType = CHAT_SOURCE_SYSTEM; + nearby_chat->addMessage(chat_msg); + } } +// [/RLVa:KB] +// if (caution) +// { +// LLChat chat(notice.getString()); +// // LLFloaterChat::addChat(chat, FALSE, FALSE); +// } } } @@ -5609,12 +5950,22 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); // only log a chat message if caution prompts are enabled - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) +// if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (gSavedSettings.getBOOL("PermissionsCautionEnabled")) || (notification["payload"]["rlv_notify"].asBoolean()) ) +// [/RLVa:KB] { // log a chat message, if appropriate notify_cautioned_script_question(notification, response, orig, allowed); } +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if ( (allowed) && (notification["payload"].has("rlv_blocked")) ) + { + RlvUtil::notifyBlocked(notification["payload"]["rlv_blocked"], LLSD().with("OBJECT", notification["payload"]["object_name"])); + } +// [/RLVa:KB] + if ( response["Mute"] ) // mute { script_question_mute(task_id,notification["payload"]["object_name"].asString()); @@ -5793,6 +6144,38 @@ void process_script_question(LLMessageSystem *msg, void **user_data) payload["object_name"] = object_name; payload["owner_name"] = owner_name; +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if (rlv_handler_t::isEnabled()) + { + RlvUtil::filterScriptQuestions(questions, payload); + + if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) ) + { + const LLViewerObject* pObj = gObjectList.findObject(taskid); + if (pObj) + { + if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) ) + { + questions &= ~(SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TAKE_CONTROLS].permbit | + SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit); + } + else + { + questions &= ~(SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TAKE_CONTROLS].permbit); + } + payload["rlv_notify"] = !pObj->permYouOwner(); + } + } + } + + if ( (!caution) && (!questions) ) + { + LLNotifications::instance().forceResponse( + LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/); + return; + } +// [/RLVa:KB] + // check whether cautions are even enabled or not const char* notification = "ScriptQuestion"; @@ -6163,6 +6546,16 @@ void send_lures(const LLSD& notification, const LLSD& response) LLAgentUI::buildSLURL(slurl); text.append("\r\n").append(slurl.getSLURLString()); +// [RLVa:KB] - Checked: RLVa-2.0.0 + // Filter the lure message if any of the recipients are IM-blocked + const LLSD& sdRecipients = notification["payload"]["ids"]; + if ( (gRlvHandler.isEnabled()) && + (std::any_of(sdRecipients.beginArray(), sdRecipients.endArray(), [](const LLSD& id) { return !RlvActions::canStartIM(id.asUUID()) || !RlvActions::canSendIM(id.asUUID()); })) ) + { + text = RlvStrings::getString(RLV_STRING_HIDDEN); + } +// [/RLVa:KB] + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_StartLure); msg->nextBlockFast(_PREHASH_AgentData); @@ -6182,10 +6575,20 @@ void send_lures(const LLSD& notification, const LLSD& response) // Record the offer. { +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvCanShowName = (!notification["payload"].has("rlv_shownames")) ? true : !notification["payload"]["rlv_shownames"].asBoolean(); +// [/RLVa:KB] LLAvatarName av_name; LLAvatarNameCache::get(target_id, &av_name); // for im log filenames LLSD args; - args["TO_NAME"] = LLSLURL("agent", target_id, "completename").getSLURLString();; +// [SL:KB] - Patch: Notification-Logging | Checked: 2012-08-23 (Catznip-3.3) +// [RLVa:KB] - Checked: RLVa-2.0.1 + args["TO_NAME"] = LLSLURL("agent", target_id, (fRlvCanShowName) ? "completename" : "rlvanonym").getSLURLString();; +// [/RLVa:KB] +// args["TO_NAME"] = LLSLURL("agent", target_id, "completename").getSLURLString();; +// [/SL:KB] +// args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();; + LLSD payload; @@ -6195,7 +6598,11 @@ void send_lures(const LLSD& notification, const LLSD& response) LLNotificationsUtil::add("TeleportOfferSent", args, payload); // Add the recepient to the recent people list. - LLRecentPeople::instance().add(target_id); +// [RLVa:KB] - Checked: RLVa-2.0.1 + if (fRlvCanShowName) + LLRecentPeople::instance().add(target_id); +// [/RLVa:KB] +// LLRecentPeople::instance().add(target_id); } } gAgent.sendReliableMessage(); @@ -6240,15 +6647,38 @@ void handle_lure(const uuid_vec_t& ids) if (!gAgent.getRegion()) return; LLSD edit_args; - edit_args["REGION"] = gAgent.getRegion()->getName(); +// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a + edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN); +// [/RLVa:KB] +// edit_args["REGION"] = gAgent.getRegion()->getName(); LLSD payload; - for (std::vector<LLUUID>::const_iterator it = ids.begin(); - it != ids.end(); - ++it) +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShouldHideNames = false; + for (const LLUUID& idAgent : ids) { - payload["ids"].append(*it); + // Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent); + if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) && + ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT_OFFER); + return; + } + } + fRlvShouldHideNames |= !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER, idAgent); + payload["ids"].append(idAgent); } + payload["rlv_shownames"] = fRlvShouldHideNames; +// [/RLVa:KB] +// for (std::vector<LLUUID>::const_iterator it = ids.begin(); +// it != ids.end(); +// ++it) +// { +// payload["ids"].append(*it); +// } if (gAgent.isGodlike()) { LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index fe3e4cdd617132e2dfdaa9be12f66c790d1954e8..f1108f9ca5aa49fd8d059dfee59fa1b010912899 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -107,6 +107,11 @@ #include "llcleanup.h" #include "llcallstack.h" #include "llmeshrepository.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvlocks.h" +// [/RLVa:KB] //#define DEBUG_UPDATE_TYPE @@ -743,6 +748,12 @@ bool LLViewerObject::isReturnable() return false; } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + if ( (RlvActions::isRlvEnabled()) && (!rlvCanDeleteOrReturn(this)) ) + { + return false; + } +// [/RLVa:KB] std::vector<LLBBox> boxes; boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned()); for (child_list_t::iterator iter = mChildList.begin(); @@ -969,7 +980,10 @@ void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& ob } } -BOOL LLViewerObject::isChild(LLViewerObject *childp) const +//BOOL LLViewerObject::isChild(LLViewerObject *childp) const +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a +BOOL LLViewerObject::isChild(const LLViewerObject *childp) const +// [/RLVa:KB] { for (child_list_t::const_iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) @@ -1496,6 +1510,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, coloru.mV[3] = 255 - coloru.mV[3]; mText->setColor(LLColor4(coloru)); mText->setString(temp_string); +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f + if (RlvActions::isRlvEnabled()) + { + mText->setObjectText(temp_string); + } +// [/RLVa:KB] mHudText = temp_string; mHudTextColor = LLColor4(coloru); @@ -1878,6 +1898,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, coloru.mV[3] = 255 - coloru.mV[3]; mText->setColor(LLColor4(coloru)); mText->setString(temp_string); +// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f + if (RlvActions::isRlvEnabled()) + { + mText->setObjectText(temp_string); + } +// [/RLVa:KB] mHudText = temp_string; mHudTextColor = LLColor4(coloru); @@ -2071,6 +2097,25 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, gObjectList.killObject(this); return retval; } +// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.1.0k) | Added: RLVa-1.1.0k + if ( (RlvActions::isRlvEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) ) + { + // Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar()) + S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getAttachmentState()); + if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD)) + { + // If this will end up on an "add locked" attachment point then treat the attach as a user action + LLNameValue* nvItem = getNVPair("AttachItemID"); + if (nvItem) + { + LLUUID idItem(nvItem->getString()); + // URGENT-RLVa: [RLVa-1.2.0] At the moment llAttachToAvatar always seems to *add* + if (idItem.notNull()) + RlvAttachmentLockWatchdog::instance().onWearAttachment(idItem, RLV_WEAR_ADD); + } + } + } +// [/RLVa:KB] sent_parentp->addChild(this); // make sure this object gets a non-damped update if (sent_parentp->mDrawable.notNull()) @@ -6382,7 +6427,10 @@ BOOL LLViewerObject::permTransfer() const // given you modify rights to. JC BOOL LLViewerObject::allowOpen() const { - return !flagInventoryEmpty() && (permYouOwner() || permModify()); +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + return !flagInventoryEmpty() && (permYouOwner() || permModify()) && ((!RlvActions::isRlvEnabled()) || (RlvActions::canEdit(this))); +// [/RLVa:KB] +// return !flagInventoryEmpty() && (permYouOwner() || permModify()); } LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo() diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 03c5403a1e596ae3cb016006d4edf0143f755897..809ad995d328082541f560aa9f272747133c7105 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -270,7 +270,10 @@ class LLViewerObject S32 numChildren() const { return mChildList.size(); } void addThisAndAllChildren(std::vector<LLViewerObject*>& objects); void addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects); - BOOL isChild(LLViewerObject *childp) const; +// BOOL isChild(LLViewerObject *childp) const; +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a + BOOL isChild(const LLViewerObject *childp) const; +// [/RLVa:KB] BOOL isSeat() const; @@ -391,7 +394,10 @@ class LLViewerObject void sendShapeUpdate(); - U8 getAttachmentState() { return mAttachmentState; } +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + U8 getAttachmentState() const { return mAttachmentState; } +// [/RLVa:KB] +// U8 getAttachmentState() { return mAttachmentState; } F32 getAppAngle() const { return mAppAngle; } F32 getPixelArea() const { return mPixelArea; } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 63e48d1dd090e18cb5e208654e91d96e2dce85ce..ac9120004bdfa628dc20b396889f92e0cdf5aaaf 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -764,6 +764,29 @@ void LLViewerObjectList::dirtyAllObjectInventory() } } +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +void LLViewerObjectList::setAllObjectDefaultTextures(U32 nChannel, bool fShowDefault) +{ + LLPipeline::sRenderTextures = !fShowDefault; + + for (LLViewerObject* pObj : mObjects) + { + LLDrawable* pDrawable = pObj->mDrawable; + if ( (pDrawable) && (!pDrawable->isDead()) ) + { + for (int idxFace = 0, cntFace = pDrawable->getNumFaces(); idxFace < cntFace; idxFace++) + { + if (LLFace* pFace = pDrawable->getFace(idxFace)) + pFace->setDefaultTexture(nChannel, fShowDefault); + } + + if (LLVOVolume* pVoVolume = pDrawable->getVOVolume()) + pVoVolume->markForUpdate(true); + } + } +} +// [/SL:KB] + void LLViewerObjectList::updateApparentAngles(LLAgent &agent) { S32 i; diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 72b2b99004435675e0ded9d1f8c4baa8318db866..d5588ab804de7531a2837d97733767a481470738 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -123,6 +123,9 @@ class LLViewerObjectList void resetObjectBeacons(); void dirtyAllObjectInventory(); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + void setAllObjectDefaultTextures(U32 nChannel, bool fShowDefault); +// [/SL:KB] void removeFromActiveList(LLViewerObject* objectp); void updateActive(LLViewerObject *objectp); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index d91d0abb991ecb81f4b7e5457a50935f48531287..67e274ed39caa160c2e46c764ef58c4dc77ac12d 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2589,6 +2589,13 @@ boost::signals2::connection LLViewerParcelMgr::setTeleportFailedCallback(telepor return mTeleportFailedSignal.connect(cb); } +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +boost::signals2::connection LLViewerParcelMgr::setTeleportDoneCallback(teleport_done_callback_t cb) +{ + return mTeleportDoneSignal.connect(cb); +} +// [/SL:KB] + /* Ok, we're notified that teleport has been finished. * We should now propagate the notification via mTeleportFinishedSignal * to all interested parties. @@ -2616,3 +2623,10 @@ void LLViewerParcelMgr::onTeleportFailed() { mTeleportFailedSignal(); } + +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +void LLViewerParcelMgr::onTeleportDone() +{ + mTeleportDoneSignal(); +} +// [/SL:KB] diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 288077fafc8a9624cf25b59446c6d37c108abf53..14b7cca7d5ddc34186a0aa3b00c5fe52ed4d6c57 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -83,6 +83,10 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> typedef boost::signals2::signal<void (const LLVector3d&, const bool&)> teleport_finished_signal_t; typedef boost::function<void()> teleport_failed_callback_t; typedef boost::signals2::signal<void()> teleport_failed_signal_t; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + typedef boost::function<void()> teleport_done_callback_t; + typedef boost::signals2::signal<void()> teleport_done_signal_t; +// [/SL:KB] static void cleanupGlobals(); @@ -284,8 +288,14 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> boost::signals2::connection setTeleportFinishedCallback(teleport_finished_callback_t cb); boost::signals2::connection setTeleportFailedCallback(teleport_failed_callback_t cb); +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + boost::signals2::connection setTeleportDoneCallback(teleport_done_callback_t cb); +// [/SL:KB] void onTeleportFinished(bool local, const LLVector3d& new_pos); void onTeleportFailed(); +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + void onTeleportDone(); +// [/SL:KB] static BOOL isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power); static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); @@ -340,6 +350,9 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> LLVector3d mTeleportInProgressPosition; teleport_finished_signal_t mTeleportFinishedSignal; teleport_failed_signal_t mTeleportFailedSignal; +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 + teleport_done_signal_t mTeleportDoneSignal; +// [/SL:KB] // Array of pieces of parcel edges to potentially draw // Has (parcels_per_edge + 1) * (parcels_per_edge + 1) elements so diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 305f891a86a2ee3c80dce32563f56462a0d38060..8893f77f8876fd52d19c521d24df09fa6438fe3c 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -76,6 +76,9 @@ LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWhiteImagep = NULL; LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultImagep = NULL; LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sSmokeImagep = NULL; LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sFlatNormalImagep = NULL; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultDiffuseImagep = NULL; +// [/SL:KB] LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap; LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL; const std::string sTesterName("TextureTester"); @@ -3584,6 +3587,14 @@ void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); if(tex) { +// [SL:KB] - Patch: Render-TextureToggle (Catznip-5.2) + // See LLViewerMediaTexture::removeFace() + if (facep->isDefaultTexture(ch)) + { + return; + } +// [/SL:KB] + mTextureList.push_back(tex);//increase the reference number by one for tex to avoid deleting it. return; } @@ -3603,9 +3614,15 @@ void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) } //virtual -void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) +//void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) +// [SL:KB] - Patch: Render-TextureToggle (Catznip-5.2) +void LLViewerMediaTexture::removeFace(U32 channel, LLFace* facep) +// [/SL:KB] { - LLViewerTexture::removeFace(ch, facep); +// [SL:KB] - Patch: Render-TextureToggle (Catznip-5.2) + LLViewerTexture::removeFace(channel, facep); +// [/SL:KB] +// LLViewerTexture::removeFace(ch, facep); const LLTextureEntry* te = facep->getTextureEntry(); if(te && te->getID().notNull()) @@ -3618,6 +3635,18 @@ void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) { if(*iter == tex) { +// [SL:KB] - Patch: Render-TextureToggle (Catznip-5.2) + // Switching to the default texture results in clearing the media textures on all prims; + // a side-effect is that we loose out on the reference to the original (non-media) + // texture potentially letting it dissapear from memory if this was the only reference to it + // (which is harmless, it just means we'll need to grab it from the cache or refetch it but + // the LL - debug - code at the bottom of addFace/removeFace disagrees so we'll hang on + // to it (and then block readding it a seond time higher up) + if (facep->isDefaultTexture(channel)) + { + return; + } +// [/SL:KB] mTextureList.erase(iter); //decrease the reference number for tex by one. return; } @@ -3662,6 +3691,13 @@ void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) } if(i == end) //no hit for this texture, remove it. { +// [SL:KB] - Patch: Render-TextureToggle (Catznip-5.2) + // See above + if (facep->isDefaultTexture(channel)) + { + return; + } +// [/SL:KB] mTextureList.erase(iter); //decrease the reference number for tex by one. return; } diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 7cbcc931b15436bf9f8da53b6c8050e0b4f42ee8..46aed42ee9ffcbe428a65b70ab1179c6c77ce0df 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -528,6 +528,9 @@ class LLViewerFetchedTexture : public LLViewerTexture static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local. static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + static LLPointer<LLViewerFetchedTexture> sDefaultDiffuseImagep; +// [/SL:KB] }; // diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ff5dff1c9b156dad0e52bdcd8af8dd76cc45476f..adc56a8622fb3d081e099247b7e494f6b651f56b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -213,6 +213,10 @@ #include "llpaneltopinfobar.h" #include "llcleanup.h" +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) +#include "rlvhandler.h" +// [/RLVa:KB] + #if LL_WINDOWS #include <tchar.h> // For Unicode conversion methods #endif @@ -4187,6 +4191,13 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent, face_hit, intersection, uv, normal, tangent); +// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c + if ( (rlv_handler_t::isEnabled()) && (found) && + (LLToolCamera::getInstance()->hasMouseCapture()) && (gKeyboard->currentMask(TRUE) & MASK_ALT) ) + { + found = NULL; + } +// [/RLVa:KB] if (!found) // if not found in HUD, look in world: { found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, @@ -4196,6 +4207,23 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de gDebugRaycastIntersection = *intersection; } } + +// [RLVa:KB] - Checked: RLVa-1.2.0 + if ( (found) && ((gTeleportDisplay) || ((rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)))) ) + { + // Allow picking if: + // - the drag-and-drop tool is active (allows inventory offers) + // - the camera tool is active + // - the pie tool is active *and* we picked our own avie (allows "mouse steering" and the self pie menu) + LLTool* pCurTool = LLToolMgr::getInstance()->getCurrentTool(); + if ( (LLToolDragAndDrop::getInstance() != pCurTool) && + (!LLToolCamera::getInstance()->hasMouseCapture()) && + ((LLToolPie::getInstance() != pCurTool) || (gAgent.getID() != found->getID())) ) + { + found = NULL; + } + } +// [/RLVa:KB] } return found; @@ -5634,6 +5662,16 @@ void LLPickInfo::fetchResults() mPickPt = mMousePt; +// [RLVa:KB] - Checked: RLVa-2.2 (@setoverlay) + if ( (gRlvHandler.isEnabled()) && (hit_object) && (!hit_object->isHUDAttachment()) ) + { + if (gRlvHandler.hitTestOverlay(mMousePt)) + { + hit_object = nullptr; + } + } +// [/RLVa:KB] + U32 te_offset = face_hit > -1 ? face_hit : 0; if (mPickParticle) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 71ff441600f8c22b803fedb78a846eb3713e1c91..83b27064de98df9e96a7ae8cfabfd0f4f5e928dc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -99,6 +99,11 @@ #include "llanimstatelabels.h" #include "lltrans.h" #include "llappearancemgr.h" +// [RLVa:KB] - Checked: RLVa-2.0.1 +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvmodifiers.h" +// [/RLVa:KB] #include "llgesturemgr.h" //needed to trigger the voice gesticulations #include "llvoiceclient.h" @@ -3024,12 +3029,23 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) const F32 time_visible = mTimeVisible.getElapsedTimeF32(); const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime"); // seconds const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShowAvTag = true, fRlvShowAvName = true; + if (RlvActions::isRlvEnabled()) + { + fRlvShowAvTag = RlvActions::canShowName(RlvActions::SNC_NAMETAG, getID()); + fRlvShowAvName = (fRlvShowAvTag) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID())); + } +// [/RLVa:KB] BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping); BOOL render_name = visible_chat || - (visible_avatar && - ((sRenderName == RENDER_NAME_ALWAYS) || - (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); + (visible_avatar && +// [RLVa:KB] - Checked: RLVa-2.0.1 + (fRlvShowAvTag) && +// [/RLVa:KB] + ((sRenderName == RENDER_NAME_ALWAYS) || + (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); // If it's your own avatar, don't draw in mouselook, and don't // draw if we're specifically hiding our own name. if (isSelf()) @@ -3059,7 +3075,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) new_name = TRUE; } - if (sRenderGroupTitles != mRenderGroupTitles) +// [RLVa:KB] - Checked: RLVa-0.2.0 + if (!fRlvShowAvName) + { + if (mRenderGroupTitles) + { + mRenderGroupTitles = FALSE; + new_name = TRUE; + } + } + else if (sRenderGroupTitles != mRenderGroupTitles) +// [/RLVa] +// if (sRenderGroupTitles != mRenderGroupTitles) { mRenderGroupTitles = sRenderGroupTitles; new_name = TRUE; @@ -3126,6 +3153,9 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // Avatars must have a first and last name if (!firstname || !lastname) return; +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShowAvName = RlvActions::canShowName(RlvActions::SNC_DEFAULT, getID()); +// [/RLVa:KB] bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); bool is_do_not_disturb = mSignaledAnimations.find(ANIM_AGENT_DO_NOT_DISTURB) != mSignaledAnimations.end(); bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); @@ -3138,7 +3168,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) { is_muted = isInMuteList(); } - bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); +// bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); +// [RLVa:KB] - Checked: RLVa-1.2.2 + bool is_friend = (fRlvShowAvName) && (LLAvatarTracker::instance().isBuddy(getID())); +// [/RLVa:KB] bool is_cloud = getIsCloud(); if (is_appearance != mNameAppearance) @@ -3203,7 +3236,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) LLFontGL::getFontSansSerifSmall()); } - if (sRenderGroupTitles +// if (sRenderGroupTitles +// [RLVa:KB] - Checked: RLVa-1.2.2 + if (sRenderGroupTitles && fRlvShowAvName +// [/RLVa:KB] && title && title->getString() && title->getString()[0] != '\0') { std::string title_str = title->getString(); @@ -3225,25 +3261,42 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) clearNameTag(); } - // Might be blank if name not available yet, that's OK - if (show_display_names) +// [RLVa:KB] - Checked: RLVa-1.2.2 + if ( (fRlvShowAvName) || (isSelf()) ) { - addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerif()); +// [/RLVa:KB] + // Might be blank if name not available yet, that's OK + if (show_display_names) + { + addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerif()); + } + // Suppress SLID display if display name matches exactly (ugh) + if (show_usernames && !av_name.isDisplayNameDefault()) + { + // *HACK: Desaturate the color + LLColor4 username_color = name_tag_color * 0.83f; + addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL, + LLFontGL::getFontSansSerifSmall()); + } +// [RLVa:KB] - Checked: RLVa-1.2.2 } - // Suppress SLID display if display name matches exactly (ugh) - if (show_usernames && !av_name.isDisplayNameDefault()) + else { - // *HACK: Desaturate the color - LLColor4 username_color = name_tag_color * 0.83f; - addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL, - LLFontGL::getFontSansSerifSmall()); + addNameTagLine(RlvStrings::getAnonym(av_name), name_tag_color, LLFontGL::NORMAL, LLFontGL::getFontSansSerif()); } +// [/RLVa:KB] } else { const LLFontGL* font = LLFontGL::getFontSansSerif(); std::string full_name = LLCacheName::buildFullName( firstname->getString(), lastname->getString() ); +// [RLVa:KB] - Checked: RLVa-1.2.2 + if ( (!fRlvShowAvName) && (!isSelf()) ) + { + full_name = RlvStrings::getAnonym(full_name); + } +// [/RLVa:KB] addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font); } @@ -3514,6 +3567,12 @@ bool LLVOAvatar::isVisuallyMuted() { muted = true; } +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + else if (isRlvSilhouette()) + { + muted = true; + } +// [/RLVa:KB] else { muted = isTooComplex(); @@ -3542,6 +3601,30 @@ bool LLVOAvatar::isInMuteList() return muted; } +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) +bool LLVOAvatar::isRlvSilhouette() +{ + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDIST)) + return false; + + static RlvCachedBehaviourModifier<float> s_nSetCamAvDist(RLV_MODIFIER_SETCAM_AVDIST); + + const F64 now = LLFrameTimer::getTotalSeconds(); + if (now >= mCachedRlvSilhouetteUpdateTime) + { + const F64 SECONDS_BETWEEN_NEARBY_UPDATES = .5f; + bool fIsRlvSilhouette = dist_vec_squared(gAgent.getPositionGlobal(), getPositionGlobal()) > s_nSetCamAvDist() * s_nSetCamAvDist(); + if (fIsRlvSilhouette != mCachedIsRlvSilhouette) + { + mCachedIsRlvSilhouette = fIsRlvSilhouette; + mNeedsImpostorUpdate = TRUE; + } + mCachedRlvSilhouetteUpdateTime = now + SECONDS_BETWEEN_NEARBY_UPDATES; + } + return mCachedIsRlvSilhouette; +} +// [/RLVa:KB] + void LLVOAvatar::updateAppearanceMessageDebugText() { S32 central_bake_version = -1; @@ -7303,6 +7386,13 @@ void LLVOAvatar::sitDown(BOOL bSitting) { // Update Movement Controls according to own Sitting mode LLFloaterMove::setSittingMode(bSitting); + +// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + if (rlv_handler_t::isEnabled()) + { + gRlvHandler.onSitOrStand(bSitting); + } +// [/RLVa:KB] } } @@ -7537,6 +7627,27 @@ LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons return NULL; } +// [SL:KB] - Patch: Appearance-RefreshAttachments | Checked: Catznip-5.3 +void LLVOAvatar::rebuildAttachments() +{ + for (const auto& kvpAttachPt : mAttachmentPoints) + { + for (LLViewerObject* pAttachObj : kvpAttachPt.second->mAttachedObjects) + { + if (LLVOVolume* pAttachVol = (pAttachObj->isMesh()) ? dynamic_cast<LLVOVolume*>(pAttachObj) : nullptr) + { + pAttachVol->forceLOD(3); + for (LLViewerObject* pChildObj : pAttachObj->getChildren()) + { + if (LLVOVolume* pChildVol = (pChildObj->isMesh()) ? dynamic_cast<LLVOVolume*>(pChildObj) : nullptr) + pAttachVol->forceLOD(3); + } + } + } + } +} +// [/SL:KB] + // virtual void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset) { @@ -7870,7 +7981,11 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) BOOL LLVOAvatar::isFullyLoaded() const { - return (mRenderUnloadedAvatar || mFullyLoaded); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-2.2 + // Changes to LLAppearanceMgr::updateAppearanceFromCOF() expect this function to actually return mFullyLoaded for gAgentAvatarp + return (mRenderUnloadedAvatar && !isSelf()) ||(mFullyLoaded); +// [/SL:KB] +// return (mRenderUnloadedAvatar || mFullyLoaded); } bool LLVOAvatar::isTooComplex() const @@ -10477,9 +10592,21 @@ void LLVOAvatar::calcMutedAVColor() if (getVisualMuteSettings() == AV_DO_NOT_RENDER) { - // explicitly not-rendered avatars are light grey - new_color = LLColor4::grey3; - change_msg = " not rendered: color is grey3"; +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + if (isRlvSilhouette()) + { + new_color = LLColor4::silhouette; + change_msg = " not rendered: color is silhouette"; + } + else + { +// [/RLVa:KB] + // explicitly not-rendered avatars are light grey + new_color = LLColor4::grey3; + change_msg = " not rendered: color is grey3"; +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + } +// [/RLVa:KB] } else if (LLMuteList::getInstance()->isMuted(av_id)) // the user blocked them { @@ -10492,8 +10619,11 @@ void LLVOAvatar::calcMutedAVColor() new_color = LLColor4::white; change_msg = " simple imposter "; } - else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 ) - { +// else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 ) +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 || mMutedAVColor == LLColor4::silhouette) +// [/RLVa:KB] + { // select a color based on the first byte of the agents uuid so any muted agent is always the same color F32 color_value = (F32) (av_id.mData[0]); F32 spectrum = (color_value / 256.0); // spectrum is between 0 and 1.f diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 00dccc5d1215c66a7503f61109583bb79b96c403..0be915d70eb2b94be76a1a2e70448872b54fe02e 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -427,6 +427,9 @@ class LLVOAvatar : U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0); bool isVisuallyMuted(); bool isInMuteList(); +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + bool isRlvSilhouette(); +// [/RLVa:KB] void forceUpdateVisualMuteSettings(); enum VisualMuteSettings @@ -436,7 +439,10 @@ class LLVOAvatar : AV_ALWAYS_RENDER = 2 }; void setVisualMuteSettings(VisualMuteSettings set); - VisualMuteSettings getVisualMuteSettings() { return mVisuallyMuteSetting; }; +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + VisualMuteSettings getVisualMuteSettings() { return (!isRlvSilhouette()) ? mVisuallyMuteSetting : AV_DO_NOT_RENDER; }; +// [/RLVa:KB] +// VisualMuteSettings getVisualMuteSettings() { return mVisuallyMuteSetting; }; U32 renderRigid(); U32 renderSkinned(); @@ -469,6 +475,10 @@ class LLVOAvatar : bool mCachedInMuteList; F64 mCachedMuteListUpdateTime; +// [RLVa:KB] - Checked: RLVa-2.2 (@setcam_avdist) + mutable bool mCachedIsRlvSilhouette = false; + mutable F64 mCachedRlvSilhouetteUpdateTime = 0.f; +// [/RLVa:KB] VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV @@ -794,6 +804,9 @@ class LLVOAvatar : /*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const; LLViewerObject * findAttachmentByID( const LLUUID & target_id ) const; LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); +// [SL:KB] - Patch: Appearance-RefreshAttachments | Checked: Catznip-5.3 + void rebuildAttachments(); +// [/SL:KB] protected: void lazyAttach(); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 63ace4fe5298931dcd190779cc4673915ef77700..49e6c48a075cbde3a132bf5b262b6bf56baf87ee 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -67,6 +67,15 @@ #include "llsdserialize.h" #include "llcallstack.h" #include "llcorehttputil.h" +// [RLVa:KB] - Checked: RLVa-2.0.2 +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvlocks.h" +// [/RLVa:KB] +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +#include "llviewerparcelmgr.h" +extern BOOL gTeleportDisplay; +// [/SL:KB] #if LL_MSVC // disable boost::lexical_cast warning @@ -162,6 +171,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : LLVOAvatar(id, pcode, regionp), +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + mAttachmentSignal(NULL), +// [/RLVa:KB] mScreenp(NULL), mLastRegionHandle(0), mRegionCrossingCount(0), @@ -223,6 +235,10 @@ void LLVOAvatarSelf::initInstance() mDebugBakedTextureTimes[i][1] = -1.0f; } +// [RLVa:KB] - Checked: 2010-12-12 (RLVa-1.2.2c) | Added: RLVa-1.2.2c + RlvAttachPtLookup::initLookupTable(); +// [/RLVa:KB] + status &= buildMenus(); if (!status) { @@ -450,6 +466,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.name =(item_params.label ); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = iter->first; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = iter->first; LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); @@ -521,6 +538,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.name =(item_params.label ); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = iter->first; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = iter->first; LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); @@ -564,6 +582,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.name =(item_params.label ); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = iter->first; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = iter->first; //* TODO: Skinning: @@ -630,6 +649,7 @@ BOOL LLVOAvatarSelf::buildMenus() item_params.label = LLTrans::getString(attachment->getName()); item_params.on_click.function_name = "Object.AttachToAvatar"; item_params.on_click.parameter = attach_index; + // [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid() item_params.on_enable.function_name = "Object.EnableWear"; item_params.on_enable.parameter = attach_index; @@ -659,6 +679,10 @@ void LLVOAvatarSelf::cleanup() LLVOAvatarSelf::~LLVOAvatarSelf() { cleanup(); + +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + delete mAttachmentSignal; +// [/RLVa:KB] } /** @@ -1052,12 +1076,25 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) } else { +// [RLVa:KB] - Checked: RLVa-2.0.2 + bool fRlvCanShowAttachment = true; + if (rlv_handler_t::isEnabled()) + { + fRlvCanShowAttachment = + (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELF)) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWSELFHEAD)) || (RLV_ATTACHGROUP_HEAD != rlvAttachGroupFromIndex(attachment->getGroup())) ); + } +// [/RLVa:KB] + switch (camera_mode) { case CAMERA_MODE_MOUSELOOK: if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) { - attachment->setAttachmentVisibility(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.2 + attachment->setAttachmentVisibility(fRlvCanShowAttachment); +// [/RLVa:KB] +// attachment->setAttachmentVisibility(TRUE); } else { @@ -1065,7 +1102,10 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) } break; default: - attachment->setAttachmentVisibility(TRUE); +// [RLVa:KB] - Checked: RLVa-2.0.2 + attachment->setAttachmentVisibility(fRlvCanShowAttachment); +// [/RLVa:KB] +// attachment->setAttachmentVisibility(TRUE); break; } } @@ -1146,6 +1186,28 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id) return NULL; } +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) +boost::signals2::connection LLVOAvatarSelf::setAttachmentCallback(const attachment_signal_t::slot_type& cb) +{ + if (!mAttachmentSignal) + mAttachmentSignal = new attachment_signal_t(); + return mAttachmentSignal->connect(cb); +} +// [/RLVa:KB] +// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +LLViewerJointAttachment* LLVOAvatarSelf::getWornAttachmentPoint(const LLUUID& idItem) const +{ + const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); + for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) + { + LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt->getAttachedObject(idItemBase)) + return pAttachPt; + } + return NULL; +} +// [/RLVa:KB] + bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const { if (!gInventory.getItem(inv_item_id)) @@ -1194,6 +1256,22 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view const LLUUID& attachment_id = viewer_object->getAttachmentItemID(); LLAppearanceMgr::instance().registerAttachment(attachment_id); updateLODRiggedAttachments(); + +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a + // NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject() + if (mAttachmentSignal) + { + (*mAttachmentSignal)(viewer_object, attachment, ACTION_ATTACH); + } + if (rlv_handler_t::isEnabled()) + { + RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment); + gRlvHandler.onAttach(viewer_object, attachment); + + if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) ) + gRlvAttachmentLocks.updateLockedHUD(); + } +// [/RLVa:KB] } return attachment; @@ -1203,6 +1281,27 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) { const LLUUID attachment_id = viewer_object->getAttachmentItemID(); + +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a + // NOTE: RLVa event handlers should be invoked *before* LLVOAvatar::detachObject() calls LLViewerJointAttachment::removeObject() + if (rlv_handler_t::isEnabled()) + { + for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt->isObjectAttached(viewer_object)) + { + RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt); + gRlvHandler.onDetach(viewer_object, pAttachPt); + } + if (mAttachmentSignal) + { + (*mAttachmentSignal)(viewer_object, pAttachPt, ACTION_DETACH); + } + } + } +// [/RLVa:KB] + if ( LLVOAvatar::detachObject(viewer_object) ) { // the simulator should automatically handle permission revocation @@ -1235,6 +1334,11 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) LLAppearanceMgr::instance().unregisterAttachment(attachment_id); } +// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + if ( (rlv_handler_t::isEnabled()) && (viewer_object->isHUDAttachment()) && (gRlvAttachmentLocks.hasLockedHUD()) ) + gRlvAttachmentLocks.updateLockedHUD(); +// [/RLVa:KB] + return TRUE; } return FALSE; @@ -1244,7 +1348,10 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) { LLInventoryItem* item = gInventory.getItem(item_id); - if (item) +// if (item) +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1c) | Added: RLVa-1.2.1c + if ( (item) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(item))) ) +// [/RLVa:KB] { gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); @@ -2863,3 +2970,57 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) } apr_file_printf( file, "\n</wearable_info>\n" ); } + +//// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +//void LLVOAvatarSelf::addPendingDetach(const LLUUID& idObject) +//{ +// if (mPendingObjectDetach.end() == std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject)) +// mPendingObjectDetach.push_back(idObject); +// +// if ((!mPendingObjectDetach.empty()) && (!mTeleportDoneConn.connected())) +// mTeleportDoneConn = LLViewerParcelMgr::instance().setTeleportDoneCallback(boost::bind(&LLVOAvatarSelf::onTeleportDone, this)); +//} +// +//bool LLVOAvatarSelf::isPendingDetach(const LLUUID& idObject) const +//{ +// return mPendingObjectDetach.end() != std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject); +//} +// +//void LLVOAvatarSelf::removePendingDetach(const LLUUID& idObject) +//{ +// auto itPendingDetach = std::find(mPendingObjectDetach.begin(), mPendingObjectDetach.end(), idObject); +// if (mPendingObjectDetach.end() != itPendingDetach) +// mPendingObjectDetach.erase(itPendingDetach); +// +// if (mPendingObjectDetach.empty()) +// mTeleportDoneConn.disconnect(); +//} +// +//void LLVOAvatarSelf::onTeleportDone() +//{ +// mTeleportDoneConn.disconnect(); +// doAfterInterval(boost::bind(&LLVOAvatarSelf::checkPendingDetach, this), 30.f); +//} +// +//void LLVOAvatarSelf::checkPendingDetach() +//{ +// if (gTeleportDisplay) +// return; +// +// for (const LLUUID& idObj : mPendingObjectDetach) +// { +// LLViewerObject* pObject = gObjectList.findObject(idObj); +// if (pObject) +// { +// gObjectList.killObject(pObject); +// if (gShowObjectUpdates) +// { +// LLColor4 color(0.f, 1.f, 0.f, 1.f); +// gPipeline.addDebugBlip(pObject->getPositionAgent(), color); +// } +// LLSelectMgr::getInstance()->removeObjectFromSelections(idObj); +// } +// } +// mPendingObjectDetach.clear(); +//} +//// [/SL:KB] diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index b0fdae9bf0e24678bd9c6b8c2d84e24eb346fded..8da24cbcfa8bdf70ad0f2d7a49008bf079beffa5 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -285,10 +285,21 @@ class LLVOAvatarSelf : BOOL isWearingAttachment(const LLUUID& inv_item_id) const; LLViewerObject* getWornAttachment(const LLUUID& inv_item_id); bool getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const; +// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i + LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const; +// [/RLVa:KB] /*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); /*virtual*/ BOOL detachObject(LLViewerObject *viewer_object); static BOOL detachAttachmentIntoInventory(const LLUUID& item_id); +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + enum EAttachAction { ACTION_ATTACH, ACTION_DETACH }; + typedef boost::signals2::signal<void (LLViewerObject*, const LLViewerJointAttachment*, EAttachAction)> attachment_signal_t; + boost::signals2::connection setAttachmentCallback(const attachment_signal_t::slot_type& cb); +// [/RLVa:KB] +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + attachment_signal_t* mAttachmentSignal; +// [/RLVa:KB] //-------------------------------------------------------------------- // HUDs //-------------------------------------------------------------------- @@ -388,6 +399,18 @@ class LLVOAvatarSelf : F32 mDebugBakedTextureTimes[LLAvatarAppearanceDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture void debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); +// [SL:KB] - Patch: Appearance-TeleportAttachKill | Checked: Catznip-4.0 +//public: +// void addPendingDetach(const LLUUID& idObject); +// bool isPendingDetach(const LLUUID& idObject) const; +// void removePendingDetach(const LLUUID& idObject); +// void checkPendingDetach(); +// void onTeleportDone(); +//protected: +// std::list<LLUUID> mPendingObjectDetach; +// boost::signals2::connection mTeleportDoneConn; +// [/SL:KB] + void appearanceChangeMetricsCoro(std::string url); bool mInitialMetric; S32 mMetricSequence; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 0a1efd564f6a7446c8eaebf58bcdc4b457996db5..19b8977e372d0f131b13bf0bcc6f50dc28de8968 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -86,6 +86,10 @@ #include "llcallstack.h" #include "llsculptidsize.h" #include "llavatarappearancedefines.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -4215,6 +4219,20 @@ U32 LLVOVolume::getHighLODTriangleCount() return ret; } +// [FS:Beq] - Patch: Appearance-RebuildAttachments | Checked: Catznip-5.3 +void LLVOVolume::forceLOD(S32 lod) +{ +// [SL:KB] - Patch: Appearance-RebuildAttachments | Checked: Catznip-5.3 + if (mDrawable.isNull()) + return; +// [/SL:KB] + + mLOD = lod; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); + mLODChanged = true; +} +// [/FS] + //static void LLVOVolume::preUpdateGeom() { @@ -4982,9 +5000,17 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LL_WARNS_ONCE("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; } - bool selected = facep->getViewerObject()->isSelected(); - - if (selected && LLSelectMgr::getInstance()->mHideSelectedObjects) +// bool selected = facep->getViewerObject()->isSelected(); +// +// if (selected && LLSelectMgr::getInstance()->mHideSelectedObjects) +// [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + const LLViewerObject* pObj = facep->getViewerObject(); + bool selected = pObj->isSelected(); + if ( (pObj->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) && + ( (!RlvActions::isRlvEnabled()) || + ( ((!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) && + (RlvActions::canEdit(pObj)) ) ) ) +// [/RVLa:KB] { return; } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 13db9c39b75bd965de5bc0ff8d68c76d09754f91..c822318e842ec929c9c45d593589150b2b8d380f 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -164,6 +164,9 @@ class LLVOVolume : public LLViewerObject LLVector3 volumeDirectionToAgent(const LLVector3& dir) const; +// [FS:Beq] - Patch: Appearance-RebuildAttachments | Checked: Catznip-5.3 + void forceLOD(S32 lod); +// [/FS] BOOL getVolumeChanged() const { return mVolumeChanged; } /*virtual*/ F32 getRadius() const { return mVObjRadius; }; diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index e7bbee5efd9b9f3d1edda598b32de3c42b02f781..6fac4cef6298c3da1e7c5f88a75add080f097f49 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -39,6 +39,10 @@ #include "lltransutil.h" #include "llviewerattachmenu.h" #include "llvoavatarself.h" +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] class LLFindOutfitItems : public LLInventoryCollectFunctor { @@ -841,6 +845,13 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu bool can_be_worn = true; +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + // We'll enable a menu option if at least one item in the selection is wearable/removable + bool rlvCanWearReplace = !RlvActions::isRlvEnabled(); + bool rlvCanWearAdd = !RlvActions::isRlvEnabled(); + bool rlvCanRemove = !RlvActions::isRlvEnabled(); +// [/RLVa:KB] + for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { LLUUID id = *it; @@ -881,6 +892,29 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu { can_be_worn = get_can_item_be_worn(item->getLinkedUUID()); } + +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + if (RlvActions::isRlvEnabled()) + { + ERlvWearMask eWearMask = RLV_WEAR_LOCKED; + switch (item->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + eWearMask = gRlvWearableLocks.canWear(item); + rlvCanRemove |= (is_worn) ? gRlvWearableLocks.canRemove(item) : false; + break; + case LLAssetType::AT_OBJECT: + eWearMask = gRlvAttachmentLocks.canAttach(item); + rlvCanRemove |= (is_worn) ? gRlvAttachmentLocks.canDetach(item) : false; + break; + default: + break; + } + rlvCanWearReplace |= ((eWearMask & RLV_WEAR_REPLACE) == RLV_WEAR_REPLACE); + rlvCanWearAdd |= ((eWearMask & RLV_WEAR_ADD) == RLV_WEAR_ADD); + } +// [/RLVa:KB] } // for bool standalone = mParent ? mParent->isStandalone() : false; @@ -888,10 +922,15 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu // *TODO: eliminate multiple traversals over the menu items setMenuItemVisible(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && can_be_worn); - setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0); +// setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0); setMenuItemVisible(menu, "wear_add", wear_add_visible); - setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids)); +// setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids)); setMenuItemVisible(menu, "wear_replace", n_worn == 0 && n_already_worn != 0 && can_be_worn); +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && rlvCanWearReplace); + setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids) && rlvCanWearAdd); + setMenuItemEnabled(menu, "wear_replace", rlvCanWearReplace); +// [/RLVa:KB] //visible only when one item selected and this item is worn setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1); setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1); @@ -902,7 +941,12 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items); setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && n_worn == n_items); setMenuItemVisible(menu, "take_off_or_detach", mask == (MASK_ATTACHMENT|MASK_CLOTHING)); - setMenuItemEnabled(menu, "take_off_or_detach", n_worn == n_items); +// setMenuItemEnabled(menu, "take_off_or_detach", n_worn == n_items); +// [RLVa:KB] - Checked: 2010-09-04 (RLVa-1.2.1a) | Added: RLVa-1.2.1a + setMenuItemEnabled(menu, "take_off", rlvCanRemove); + setMenuItemEnabled(menu, "detach", rlvCanRemove); + setMenuItemEnabled(menu, "take_off_or_detach", (n_worn == n_items) && (rlvCanRemove)); +// [/RLVa:KB] setMenuItemVisible(menu, "object_profile", !standalone); setMenuItemEnabled(menu, "object_profile", n_items == 1); setMenuItemVisible(menu, "--no options--", FALSE); diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index b61fbbd07304cad9739741cb24d7698389f5b0ef..10e25bb86b3600c447ff9a3709b5f2e120f1f256 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -99,7 +99,23 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID { BOOL isNewWearable = FALSE; LLWearableArrivedData* data = (LLWearableArrivedData*) userdata; - LLViewerWearable* wearable = NULL; // NULL indicates failure +// LLViewerWearable* wearable = NULL; // NULL indicates failure +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-08-13 (Catznip-2.1) + LLViewerWearable* wearable = get_if_there(LLWearableList::instance().mList, uuid, (LLViewerWearable*)NULL); + if (wearable) + { + LL_DEBUGS("Wearable") << "processGetAssetReply()" << LL_ENDL; + LL_DEBUGS("Wearable") << wearable << LL_ENDL; + + if(data->mCallback) + { + data->mCallback(wearable, data->mUserdata); + } + delete data; + + return; + } +// [/SL:KB] LLAvatarAppearance *avatarp = data->mAvatarp; if( !filename ) diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 4b4393b07b9996341347af02dde54f58cc2b73f5..5a17cc2d17bddc963802b3adbe40dcb35e3b3ac1 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -59,6 +59,10 @@ #include "curl/curl.h" #include "llstreamtools.h" +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +#include <boost/algorithm/string.hpp> +// [/RLVa:KB] + LLWLParamManager::LLWLParamManager() : //set the defaults for the controls @@ -653,6 +657,19 @@ void LLWLParamManager::getPresetNames(preset_name_list_t& region, preset_name_li } } +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +const std::string& LLWLParamManager::findPreset(const std::string& strPresetName, LLEnvKey::EScope eScope) +{ + for (std::map<LLWLParamKey, LLWLParamSet>::const_iterator itList = mParamList.begin(); itList != mParamList.end(); itList++) + { + const LLWLParamKey& wlKey = itList->first; + if ( (wlKey.scope == eScope) && (boost::iequals(wlKey.name, strPresetName)) ) + return wlKey.name; + } + return LLStringUtil::null; +} +// [/RLVa:KB] + void LLWLParamManager::getUserPresetNames(preset_name_list_t& user) const { preset_name_list_t region, sys; // unused diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h index 61f86b747fe05dccd337ea3d13de28b5426ab288..7c024213b7654154d9ccc283fbc4ea4d032257a5 100644 --- a/indra/newview/llwlparammanager.h +++ b/indra/newview/llwlparammanager.h @@ -199,6 +199,10 @@ class LLWLParamManager : public LLSingleton<LLWLParamManager> /// @return user and system preset names as a single list void getPresetNames(preset_name_list_t& region, preset_name_list_t& user, preset_name_list_t& sys) const; +// [RLVa:KB] - Checked: 2011-09-04 (RLVa-1.4.1a) | Added: RLVa-1.4.1a + const std::string& findPreset(const std::string& strPresetName, LLEnvKey::EScope eScope); +// [/RLVa:KB] + /// @return user preset names void getUserPresetNames(preset_name_list_t& user) const; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 89f5eb86b32269000a2999edb035baf3a6ba897c..2896983c270535752365e00ff38f4b1165f41341 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1327,6 +1327,35 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi } } +// [RLVa:KB] - Checked: RLVa-2.0.1 +bool LLWorld::getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const +{ + for (const LLCharacter* pCharacter : LLCharacter::sInstances) + { + const LLVOAvatar* pAvatar = static_cast<const LLVOAvatar*>(pCharacter); + if ( (!pAvatar->isDead()) && (!pAvatar->mIsDummy) && (!pAvatar->isOrphaned()) && (idAvatar == pAvatar->getID()) ) + { + posAvatar = pAvatar->getPositionGlobal(); + return true; + } + } + + for (const LLViewerRegion* pRegion : LLWorld::getInstance()->getRegionList()) + { + for (S32 idxAgent = 0, cntAgent = pRegion->mMapAvatarIDs.size(); idxAgent < cntAgent; ++idxAgent) + { + if (idAvatar == pRegion->mMapAvatarIDs[idxAgent]) + { + posAvatar = unpackLocalToGlobalPosition(pRegion->mMapAvatars[idxAgent], pRegion->getOriginGlobal()); + return true; + } + } + } + + return false; +} +// [/RLVa:KB] + bool LLWorld::isRegionListed(const LLViewerRegion* region) const { region_list_t::const_iterator it = find(mRegionList.begin(), mRegionList.end(), region); diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 993fbfb2cc3b73e2627512bfee95b1e5fb21cb83..3fa5f46876e99b48ee7d9199c6c68babf1a4a359 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -162,6 +162,9 @@ class LLWorld : public LLSingleton<LLWorld> uuid_vec_t* avatar_ids = NULL, std::vector<LLVector3d>* positions = NULL, const LLVector3d& relative_to = LLVector3d(), F32 radius = FLT_MAX) const; +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const; +// [/RLVa:KB] // Returns 'true' if the region is in mRegionList, // 'false' if the region has been removed due to region change diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index a6df0792233581c1aabe4c1c268298b99a0003c4..0754e31c91273260426b7e058aef078135307b1e 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -55,6 +55,10 @@ #include "llviewerregion.h" #include "llviewerwindow.h" #include "lltrans.h" +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] #include "llglheaders.h" @@ -459,7 +463,10 @@ void LLWorldMapView::draw() { mesg = info->getName(); } - if (!mesg.empty()) +// if (!mesg.empty()) +// [RLVa:KB] - Checked: 2012-02-08 (RLVa-1.4.5) | Added: RLVa-1.4.5 + if ( (!mesg.empty()) && (RlvActions::canShowLocation()) ) +// [/RLVa:KB] { font->renderUTF8( mesg, 0, @@ -996,7 +1003,10 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& text_x = llclamp(text_x, half_text_width + TEXT_PADDING, getRect().getWidth() - half_text_width - TEXT_PADDING); text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - font->getLineHeight() - TEXT_PADDING - vert_offset); - if (label != "") +// if (label != "") +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.4.5) | Added: RLVa-1.0.0 + if ( (label != "") && (RlvActions::canShowLocation()) ) +// [/RLVa:KB] { font->renderUTF8( label, 0, @@ -1056,7 +1066,12 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask ) { LLViewerRegion *region = gAgent.getRegion(); - std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str()); +// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.4.5) | Modified: RLVa-1.4.5 + std::string message = llformat("%s (%s)", + (RlvActions::canShowLocation()) ? info->getName().c_str() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), + info->getAccessString().c_str()); +// [/RLVa:KB] +// std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str()); if (!info->isDown()) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index bec33790bd9edc5dc6e51cd6fba7cf408641b662..cbf477d76ffe1ddecc9992899438ff7ae08f1b53 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -115,6 +115,10 @@ #include "llscenemonitor.h" #include "llprogressview.h" #include "llcleanup.h" +// [RLVa:KB] - Checked: RLVa-2.0.0 +#include "rlvactions.h" +#include "rlvlocks.h" +// [/RLVa:KB] #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -137,6 +141,9 @@ bool LLPipeline::RenderDeferred; F32 LLPipeline::RenderDeferredSunWash; U32 LLPipeline::RenderFSAASamples; U32 LLPipeline::RenderResolutionDivisor; +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 +F32 LLPipeline::RenderResolutionMultiplier; +// [/SL:KB] bool LLPipeline::RenderUIBuffer; S32 LLPipeline::RenderShadowDetail; bool LLPipeline::RenderDeferredSSAO; @@ -398,6 +405,9 @@ bool LLPipeline::sMemAllocationThrottled = false; S32 LLPipeline::sVisibleLightCount = 0; F32 LLPipeline::sMinRenderSize = 0.f; bool LLPipeline::sRenderingHUDs; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) +bool LLPipeline::sRenderTextures = true; +// [/SL:KB] // EventHost API LLPipeline listener. static LLPipelineListener sPipelineListener; @@ -579,6 +589,9 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderDeferredSunWash"); connectRefreshCachedSettingsSafe("RenderFSAASamples"); connectRefreshCachedSettingsSafe("RenderResolutionDivisor"); +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + connectRefreshCachedSettingsSafe("RenderResolutionMultiplier"); +// [/SL:KB] connectRefreshCachedSettingsSafe("RenderUIBuffer"); connectRefreshCachedSettingsSafe("RenderShadowDetail"); connectRefreshCachedSettingsSafe("RenderDeferredSSAO"); @@ -785,6 +798,19 @@ void LLPipeline::resizeScreenTexture() GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + if ( (RenderResolutionDivisor > 1) && (RenderResolutionDivisor < resX) && (RenderResolutionDivisor < resY) ) + { + resX /= RenderResolutionDivisor; + resY /= RenderResolutionDivisor; + } + else if (RenderResolutionMultiplier != 1.f) + { + resX *= RenderResolutionMultiplier; + resY *= RenderResolutionMultiplier; + } +// [/SL:KB] + if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) { releaseScreenBuffers(); @@ -921,6 +947,13 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) resX /= res_mod; resY /= res_mod; } +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + else if (RenderResolutionMultiplier != 1.f) + { + resX *= RenderResolutionMultiplier; + resY *= RenderResolutionMultiplier; + } +// [/SL:KB] if (RenderUIBuffer) { @@ -1099,6 +1132,9 @@ void LLPipeline::refreshCachedSettings() RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash"); RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples"); RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor"); +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + RenderResolutionMultiplier = gSavedSettings.getF32("RenderResolutionMultiplier"); +// [/SL:KB] RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer"); RenderShadowDetail = gSavedSettings.getS32("RenderShadowDetail"); RenderDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO"); @@ -3551,8 +3587,15 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) if (LLSelectMgr::getInstance()->mHideSelectedObjects) { - if (drawablep->getVObj().notNull() && - drawablep->getVObj()->isSelected()) +// if (drawablep->getVObj().notNull() && +// drawablep->getVObj()->isSelected()) +// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f + const LLViewerObject* pObj = drawablep->getVObj(); + if ( (pObj) && (pObj->isSelected()) && + ( (!RlvActions::isRlvEnabled()) || + ( ((!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj->getRootEdit()))) && + (RlvActions::canEdit(pObj)) ) ) ) +// [/RVLa:KB] { return; } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 29fe1cbd33f50ffdfb76da0fe2b638a9da435bc3..fc79ae5016d159986099e1aa3bf20eb832679f38 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -589,6 +589,9 @@ class LLPipeline static S32 sVisibleLightCount; static F32 sMinRenderSize; static bool sRenderingHUDs; +// [SL:KB] - Patch: Render-TextureToggle (Catznip-4.0) + static bool sRenderTextures; +// [/SL:KB] static LLTrace::EventStatHandle<S64> sStatBatchSize; @@ -870,6 +873,9 @@ class LLPipeline static F32 RenderDeferredSunWash; static U32 RenderFSAASamples; static U32 RenderResolutionDivisor; +// [SL:KB] - Patch: Settings-RenderResolutionMultiplier | Checked: Catznip-5.4 + static F32 RenderResolutionMultiplier; +// [/SL:KB] static bool RenderUIBuffer; static S32 RenderShadowDetail; static bool RenderDeferredSSAO; diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5c5dc52a6ef18ece4eae1823d320e27a0c9d77a --- /dev/null +++ b/indra/newview/rlvactions.cpp @@ -0,0 +1,581 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llimview.h" +#include "llviewercamera.h" +#include "llvoavatarself.h" +#include "llworld.h" + +#include "rlvactions.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvinventory.h" +#include "rlvmodifiers.h" + +// ============================================================================ +// Camera +// + +bool RlvActions::canChangeCameraFOV(const LLUUID& idRlvObject) +{ + // NOTE: if an object has exclusive camera control then all other objects are locked out + return (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM)); +} + +bool RlvActions::canChangeCameraPreset(const LLUUID& idRlvObject) +{ + // NOTE: if an object has exclusive camera control then all other objects are locked out + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM)) ) && + (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET)); +} + +bool RlvActions::canChangeToMouselook() +{ + // User can switch to mouselook if: + // - not specifically prevented from going into mouselook (NOTE: if an object has exclusive camera control only that object can prevent mouselook) + // - there is no minimum camera distance defined (or it's higher than > 0m) + const RlvBehaviourModifier* pCamDistMinModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN); + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_MOUSELOOK) : !gRlvHandler.hasBehaviour(pCamDistMinModifier->getPrimaryObject(), RLV_BHVR_SETCAM_MOUSELOOK) ) && + ( (!pCamDistMinModifier->hasValue()) || (pCamDistMinModifier->getValue<float>() == 0.f) ); +} + +bool RlvActions::isCameraDistanceClamped() +{ + return + (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX)) || + (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMAX)); +} + +bool RlvActions::isCameraFOVClamped() +{ + return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX)); +} + +bool RlvActions::isCameraPresetLocked() +{ + return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET)); +} + +bool RlvActions::getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax) +{ + bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX); + if ( (fDistMin) || (fDistMax) ) + { + static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_AVDISTMIN); + static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_AVDISTMAX); + + nDistMax = (fDistMax) ? sCamDistMax : F32_MAX; + nDistMin = (fDistMin) ? sCamDistMin : 0.0; + return true; + } + return false; +} + +bool RlvActions::getCameraOriginDistanceLimits(float& nDistMin, float& nDistMax) +{ + bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_ORIGINDISTMAX); + if ( (fDistMin) || (fDistMax) ) + { + static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_ORIGINDISTMIN); + static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_ORIGINDISTMAX); + + nDistMax = (fDistMax) ? sCamDistMax : F32_MAX; + nDistMin = (fDistMin) ? sCamDistMin : 0.0; + return true; + } + return false; +} + +bool RlvActions::getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax) +{ + bool fClampMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN), fClampMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX); + if ( (fClampMin) || (fClampMax) ) + { + static RlvCachedBehaviourModifier<float> sCamFovMin(RLV_MODIFIER_SETCAM_FOVMIN); + static RlvCachedBehaviourModifier<float> sCamFovMax(RLV_MODIFIER_SETCAM_FOVMAX); + + nFOVMin = (fClampMin) ? sCamFovMin : LLViewerCamera::getInstance()->getMinView(); + nFOVMax = (fClampMax) ? sCamFovMax : LLViewerCamera::getInstance()->getMaxView(); + return true; + } + return false; +} + +// ============================================================================ +// Communication/Avatar interaction +// + +bool RlvActions::s_BlockNamesContexts[SNC_COUNT] = { 0 }; + +bool RlvActions::canChangeActiveGroup(const LLUUID& idRlvObject) +{ + // User can change their active group if: + // - not specifically restricted (by another object that the one specified) from changing their active group + return (idRlvObject.isNull()) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP) : !gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETGROUP, idRlvObject); +} + +// Little helper function to check the IM exclusion range for @recvim, @sendim and @startim (returns: min_dist <= (pos user - pos target) <= max_dist) +static bool rlvCheckAvatarIMDistance(const LLUUID& idAvatar, ERlvBehaviourModifier eModDistMin, ERlvBehaviourModifier eModDistMax) +{ + // | no limits | minimum set | min+max set | !fHasMin | !fHasMax = INF | fHasMax + // -------------------------------------------------------------- ------------------------------------ + // dist <= min <= max | block | block | block | F | F | F + // min <= dist <= max | block | allow | allow | F | T | T + // min <= max <= dist | block | allow | block | F | ^ (see above) | F + // off-region | block | allow | block | F | ^ (see above) | F + + const RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax); + if (pBhvrModDistMin->hasValue()) + { + LLVector3d posAgent; bool fHasMax = pBhvrModDistMax->hasValue(); + float nMinDist = pBhvrModDistMin->getValue<float>(), nMaxDist = (fHasMax) ? pBhvrModDistMax->getValue<float>() : std::numeric_limits<float>::max(); + float nDist = (LLWorld::getInstance()->getAvatar(idAvatar, posAgent)) ? llabs(dist_vec_squared(gAgent.getPositionGlobal(), posAgent)) : std::numeric_limits<float>::max(); + return (nMinDist < nMaxDist) && (nMinDist <= nDist) && (nDist <= nMaxDist); + } + return false; +} + +bool RlvActions::canReceiveIM(const LLUUID& idSender) +{ + // User can receive an IM from "sender" (could be an agent or a group) if: + // - not generally restricted from receiving IMs (or the sender is an exception or inside the exclusion range) + // - not specifically restricted from receiving an IM from the sender + return + (!isRlvEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, idSender)) || (rlvCheckAvatarIMDistance(idSender, RLV_MODIFIER_RECVIMDISTMIN, RLV_MODIFIER_RECVIMDISTMAX)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) || (!gRlvHandler.isException(RLV_BHVR_RECVIMFROM, idSender)) ) ); +} + +bool RlvActions::canPlayGestures() +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDGESTURE)); +} + +bool RlvActions::canSendChannel(int nChannel) +{ + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, nChannel)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNELEXCEPT)) || (!gRlvHandler.isException(RLV_BHVR_SENDCHANNELEXCEPT, nChannel)) ); +} + +bool RlvActions::canSendIM(const LLUUID& idRecipient) +{ + // User can send an IM to "recipient" (could be an agent or a group) if: + // - not generally restricted from sending IMs (or the recipient is an exception or inside the exclusion range) + // - not specifically restricted from sending an IM to the recipient + return + (!isRlvEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.isException(RLV_BHVR_SENDIM, idRecipient)) || (rlvCheckAvatarIMDistance(idRecipient, RLV_MODIFIER_SENDIMDISTMIN, RLV_MODIFIER_SENDIMDISTMAX)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) || (!gRlvHandler.isException(RLV_BHVR_SENDIMTO, idRecipient)) ) ); +} + +bool RlvActions::canStartIM(const LLUUID& idRecipient, bool fIgnoreOpen) +{ + // User can start an IM session with "recipient" (could be an agent or a group) if: + // - not generally restricted from starting IM sessions (or the recipient is an exception or inside the exclusion range) + // - not specifically restricted from starting an IM session with the recipient + // - the session already exists + return + (!isRlvEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIM)) || (gRlvHandler.isException(RLV_BHVR_STARTIM, idRecipient)) || (rlvCheckAvatarIMDistance(idRecipient, RLV_MODIFIER_STARTIMDISTMIN, RLV_MODIFIER_STARTIMDISTMAX)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIMTO)) || (!gRlvHandler.isException(RLV_BHVR_STARTIMTO, idRecipient)) ) ) || + ( (!fIgnoreOpen) && ((hasOpenP2PSession(idRecipient)) || (hasOpenGroupSession(idRecipient))) ); +} + +bool RlvActions::canShowName(EShowNamesContext eContext, const LLUUID& idAgent) +{ + // Handle most common case upfront + if (!s_BlockNamesContexts[eContext]) + return true; + + if (idAgent.notNull()) + { + switch (eContext) + { + // Show/hide avatar nametag + case SNC_NAMETAG: + return (gRlvHandler.isException(RLV_BHVR_SHOWNAMETAGS, idAgent)) || (gAgentID == idAgent); + // Show/hide avatar name + case SNC_DEFAULT: + case SNC_TELEPORTOFFER: + case SNC_TELEPORTREQUEST: + return gRlvHandler.isException(RLV_BHVR_SHOWNAMES, idAgent) || (gAgentID == idAgent); + } + } + return false; +} + +bool RlvActions::canShowNearbyAgents() +{ + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNEARBY); +} + +// Handles: @chatwhisper, @chatnormal and @chatshout +EChatType RlvActions::checkChatVolume(EChatType chatType) +{ + // In vs Bhvr | whisper | normal | shout | n+w | n+s | s+w | s+n+w | + // --------------------------------------------------------------------------------- + // whisper | normal | - | - | normal | - | normal | normal | + // normal | - | whisper | - | whisper | whisper | - | whisper | + // shout | - | whisper | normal | whisper | whisper | normal | whisper | + + RlvHandler& rlvHandler = RlvHandler::instance(); + if ( ((CHAT_TYPE_SHOUT == chatType) || (CHAT_TYPE_NORMAL == chatType)) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) + chatType = CHAT_TYPE_WHISPER; + else if ( (CHAT_TYPE_SHOUT == chatType) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) + chatType = CHAT_TYPE_NORMAL; + else if ( (CHAT_TYPE_WHISPER == chatType) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) + chatType = CHAT_TYPE_NORMAL; + return chatType; +} + +// ============================================================================ +// Inventory +// + +bool RlvActions::canPasteInventory(const LLInventoryCategory* pSourceCat, const LLInventoryCategory* pDestCat) +{ + // The user can paste the specified object into the destination if: + // - the source and destination are subject to the same lock type (or none at all) => NOTE: this happens to be the same logic we use for moving + return (!isRlvEnabled()) || + ( (pSourceCat) && (pDestCat) && ((!RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().canMoveFolder(pSourceCat->getUUID(), pDestCat->getUUID()))) ); +} + +bool RlvActions::canPasteInventory(const LLInventoryItem* pSourceItem, const LLInventoryCategory* pDestCat) +{ + // The user can paste the specified object into the destination if: + // - the source and destination are subject to the same lock type (or none at all) => NOTE: this happens to be the same logic we use for moving + return (!isRlvEnabled()) || + ( (pSourceItem) && (pDestCat) && ((!RlvFolderLocks::instance().hasLockedFolder(RLV_LOCK_ANY)) || (RlvFolderLocks::instance().canMoveItem(pSourceItem->getUUID(), pDestCat->getUUID()))) ); +} + +bool RlvActions::canPreviewTextures() +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)); +} + +// ============================================================================ +// Movement +// + +bool RlvActions::canAcceptTpOffer(const LLUUID& idSender) +{ + return ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) || (gRlvHandler.isException(RLV_BHVR_TPLURE, idSender))) && (canStand()); +} + +bool RlvActions::autoAcceptTeleportOffer(const LLUUID& idSender) +{ + return ((idSender.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, idSender))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)); +} + +bool RlvActions::canAcceptTpRequest(const LLUUID& idSender) +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_TPREQUEST)) || (gRlvHandler.isException(RLV_BHVR_TPREQUEST, idSender)); +} + +bool RlvActions::autoAcceptTeleportRequest(const LLUUID& idRequester) +{ + return ((idRequester.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTPREQUEST, idRequester))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTPREQUEST)); +} + +bool RlvActions::canFly() +{ + return (!gRlvHandler.getCurrentCommand()) ? !gRlvHandler.hasBehaviour(RLV_BHVR_FLY) : !gRlvHandler.hasBehaviourExcept(RLV_BHVR_FLY, gRlvHandler.getCurrentObject()); +} + +bool RlvActions::canFly(const LLUUID& idRlvObjExcept) +{ + return !gRlvHandler.hasBehaviourExcept(RLV_BHVR_FLY, idRlvObjExcept); +} + +bool RlvActions::canJump() +{ + return !gRlvHandler.hasBehaviour(RLV_BHVR_JUMP); +} + +// ============================================================================ +// Teleporting +// + +bool RlvActions::canTeleportToLocal(const LLVector3d& posGlobal) +{ + // User can initiate a local teleport if: + // - can stand up (or isn't sitting) + // - not restricted from "sit teleporting" (or the destination is within the allowed xyz-radius) + // - not restricted from teleporting locally (or the destination is within the allowed xy-radius) + // NOTE: if we're teleporting due to an active command we should disregard any restrictions from the same object + const LLUUID& idRlvObjExcept = gRlvHandler.getCurrentObject(); + bool fCanTeleport = RlvActions::canStand(idRlvObjExcept); + if ( (fCanTeleport) && (gRlvHandler.hasBehaviourExcept(RLV_BHVR_SITTP, idRlvObjExcept)) ) + { + const F32 nDistSq = (posGlobal - gAgent.getPositionGlobal()).lengthSquared(); + const F32 nSitTpDist = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SITTPDIST)->getValue<F32>(); + fCanTeleport = nDistSq < nSitTpDist * nSitTpDist; + } + if ( (fCanTeleport) && (gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOCAL, idRlvObjExcept)) ) + { + const F32 nDistSq = (LLVector2(posGlobal.mdV[0], posGlobal.mdV[1]) - LLVector2(gAgent.getPositionGlobal().mdV[0], gAgent.getPositionGlobal().mdV[1])).lengthSquared(); + const F32 nTpLocalDist = llmin(RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_TPLOCALDIST)->getValue<float>(), RLV_MODIFIER_TPLOCAL_DEFAULT); + fCanTeleport = nDistSq < nTpLocalDist * nTpLocalDist; + } + return fCanTeleport; +} + +bool RlvActions::canTeleportToLocation() +{ + // NOTE: if we're teleporting due to an active command we should disregard any restrictions from the same object + const LLUUID& idRlvObjExcept = gRlvHandler.getCurrentObject(); + return (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOC, idRlvObjExcept)) && (RlvActions::canStand(idRlvObjExcept)); +} + +bool RlvActions::isLocalTp(const LLVector3d& posGlobal) +{ + const F32 nDistSq = (LLVector2(posGlobal.mdV[0], posGlobal.mdV[1]) - LLVector2(gAgent.getPositionGlobal().mdV[0], gAgent.getPositionGlobal().mdV[1])).lengthSquared(); + return nDistSq < RLV_MODIFIER_TPLOCAL_DEFAULT * RLV_MODIFIER_TPLOCAL_DEFAULT; +} + +// ============================================================================ +// World interaction +// + +bool RlvActions::canBuild() +{ + // User can access the build floater if: + // - allowed to edit existing objects OR + // - allowed to rez/create objects + return + (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || + (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)); +} + +// Handles: @edit and @editobj +bool RlvActions::canEdit(const LLViewerObject* pObj) +{ + // User can edit the specified object if: + // - not generally restricted from editing (or the object's root is an exception) + // - not specifically restricted from editing this object's root + + // NOTE-RLVa: edit checks should *never* be subject to @fartouch distance checks since we don't have the pick offset so + // instead just implicitly rely on the presence of a (transient) selection + return + (pObj) && + ( (!RlvHandler::instance().hasBehaviour(RLV_BHVR_EDIT)) || (RlvHandler::instance().isException(RLV_BHVR_EDIT, pObj->getRootEdit()->getID())) ) && + ( (!RlvHandler::instance().hasBehaviour(RLV_BHVR_EDITOBJ)) || (!RlvHandler::instance().isException(RLV_BHVR_EDITOBJ, pObj->getRootEdit()->getID())) ); +} + +// Handles: @fartouch and @interact +bool RlvActions::canInteract(const LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) +{ + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + + // User can interact with the specified object if: + // - not interaction restricted (or the specified object is a HUD attachment) + // - not prevented from touching faraway objects (or the object's center + pick offset is within range) + RlvHandler& rlvHandler = RlvHandler::instance(); + return + (!pObj) || + ( ( (!rlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) || (pObj->isHUDAttachment())) && + ( (!rlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) || (pObj->isHUDAttachment()) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= s_nFartouchDist * s_nFartouchDist)) ); +} + +bool RlvActions::canRez() +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)); +} + +bool RlvActions::canGroundSit() +{ + // User can sit on the ground if: + // - not prevented from sitting + // - not prevented from standing up or not currently sitting + return (!hasBehaviour(RLV_BHVR_SIT)) && (canStand()); +} + +bool RlvActions::canSit(const LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) +{ + // User can sit on the specified object if: + // - not prevented from sitting + // - not prevented from standing up or not currently sitting + // - not standtp restricted or not currently sitting (if the user is sitting and tried to sit elsewhere the tp would just kick in) + // - not a regular sit (i.e. due to @sit:<uuid>=force) + // - not @sittp=n or @fartouch=n restricted or if they clicked on a point within the allowed radius + static RlvCachedBehaviourModifier<float> s_nFarTouchDist(RLV_MODIFIER_FARTOUCHDIST); + static RlvCachedBehaviourModifier<float> s_nSitTpDist(RLV_MODIFIER_SITTPDIST); + return + ( (pObj) && (LL_PCODE_VOLUME == pObj->getPCode()) ) && + (!hasBehaviour(RLV_BHVR_SIT)) && + ( ((!hasBehaviour(RLV_BHVR_UNSIT)) && (!hasBehaviour(RLV_BHVR_STANDTP))) || + ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())) ) && + ( ( (NULL != gRlvHandler.getCurrentCommand()) && (RLV_BHVR_SIT == gRlvHandler.getCurrentCommand()->getBehaviourType()) ) || + ( ((!hasBehaviour(RLV_BHVR_SITTP)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < s_nSitTpDist * s_nSitTpDist)) && + ((!hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < s_nFarTouchDist * s_nFarTouchDist)) ) ); +} + +// Handles: @showhovertextall, @showhovertextworld, @showhovertexthud and @showhovertext +bool RlvActions::canShowHoverText(const LLViewerObject *pObj) +{ + // User cannot see this object's hover text if: + // - prevented from seeing any hover text + // - prevented from seeing hover text on world objects (= non-HUD attachments) + // - prevented from seeing hover text on HUD objects + // - specifically prevented from seeing that object's hover text) + // -> NOTE-RLVa: this is object-specific (as opposed to touch restricts which are linkset-wide) + RlvHandler& rlvHandler = RlvHandler::instance(); + return + ( (!pObj) || (LL_PCODE_VOLUME != pObj->getPCode()) || + !( (rlvHandler.hasBehaviour(RLV_BHVR_SHOWHOVERTEXTALL)) || + ( (rlvHandler.hasBehaviour(RLV_BHVR_SHOWHOVERTEXTWORLD)) && (!pObj->isHUDAttachment()) ) || + ( (rlvHandler.hasBehaviour(RLV_BHVR_SHOWHOVERTEXTHUD)) && (pObj->isHUDAttachment()) ) || + (rlvHandler.isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID(), RLV_CHECK_PERMISSIVE)) ) ); +} + +// Handles: @touchall, @touchthis, @touchworld, @touchattach, @touchattachself, @touchattachother, @touchhud, @touchme and @fartouch +bool RlvActions::canTouch(const LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) +{ + static RlvCachedBehaviourModifier<float> s_nFartouchDist(RLV_MODIFIER_FARTOUCHDIST); + + // User can touch a + // (1) World object if + // - a) not prevented from touching any object + // - b) not specifically prevented from touching that object + // - c) not prevented from touching world objects (or the object is an exception) + // - h) not prevented from touching faraway objects (or the object's center + pick offset is within range) + // - i) specifically allowed to touch that object (overrides all restrictions) + // (2) Attachment (on another avatar) + // - a) not prevented from touching any object + // - b) not specifically prevented from touching that object + // - d) not prevented from touching attachments (or the attachment is an exception) + // - e) not prevented from touching other avatar's attachments (or the attachment is an exception) + // - h) not prevented from touching faraway objects (or the attachment's center + pick offset is within range) + // - i) specifically allowed to touch that object (overrides all restrictions) + // (3) Attachment (on own avatar) + // - a) not prevented from touching any object + // - b) not specifically prevented from touching that object + // - d) not prevented from touching attachments (or the attachment is an exception) + // - f) not prevented from touching their own avatar's attachments (or the attachment is an exception) + // - h) not prevented from touching faraway objects (or the attachment's center + pick offset is within range) + // - i) specifically allowed to touch that object (overrides all restrictions) + // (4) Attachment (on HUD) + // - b) not specifically prevented from touching that object + // - g) not prevented from touching their own HUD attachments (or the attachment is an exception) + // - i) specifically allowed to touch that object (overrides all restrictions) + + // NOTE-RLVa: * touch restrictions apply linkset-wide (as opposed to, for instance, hover text which is object-specific) but only the root object's restrictions are tested + // * @touchall affects world objects and world attachments (self and others') but >not< HUD attachments + // * @fartouch distance matches against the specified object + pick offset (so >not< the linkset root) + // * @touchattachother exceptions are only checked under the general @touchattach exceptions + // * @touchattachself exceptions are only checked under the general @touchattach exceptions + // * @touchme in any object of a linkset affects that entire linkset (= if you can specifically touch one prim in a linkset you can touch that entire linkset) + const LLUUID& idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null; + + RlvHandler& rlvHandler = RlvHandler::instance(); + // Short circuit test for (1/2/3/4.a) and (1/2/3/4.b) + bool fCanTouch = + (idRoot.notNull()) && + ( (pObj->isHUDAttachment()) || (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHALL)) ) && + ( (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHTHIS)) || (!rlvHandler.isException(RLV_BHVR_TOUCHTHIS, idRoot, RLV_CHECK_PERMISSIVE)) ); + if (fCanTouch) + { + if ( (!pObj->isAttachment()) || (!pObj->permYouOwner()) ) + { + // Rezzed or attachment worn by other - test for (1.c), (2.d), (2.e) and (1/2.h) + fCanTouch = + ( (!pObj->isAttachment()) ? (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHWORLD)) || (rlvHandler.isException(RLV_BHVR_TOUCHWORLD, idRoot, RLV_CHECK_PERMISSIVE)) + : ((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACH)) && (!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACHOTHER))) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE)) ) && + ( (!rlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) || (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= s_nFartouchDist * s_nFartouchDist) ); + } + else if (!pObj->isHUDAttachment()) + { + // Regular attachment worn by this avie - test for (3.d), (3.e) and (3.h) + fCanTouch = + ((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACH)) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE))) && + ((!rlvHandler.hasBehaviour(RLV_BHVR_TOUCHATTACHSELF)) || (rlvHandler.isException(RLV_BHVR_TOUCHATTACH, idRoot, RLV_CHECK_PERMISSIVE))); + } + else + { + // HUD attachment - test for (4.g) + fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || (rlvHandler.isException(RLV_BHVR_TOUCHHUD, idRoot, RLV_CHECK_PERMISSIVE)); + } + } + // Post-check for (1/2/3/4i) + if ( (!fCanTouch) && (hasBehaviour(RLV_BHVR_TOUCHME)) ) + fCanTouch = rlvHandler.hasBehaviourRoot(idRoot, RLV_BHVR_TOUCHME); + return fCanTouch; +} + +bool RlvActions::canStand() +{ + // NOTE: return FALSE only if we're @unsit=n restricted and the avie is currently sitting on something and TRUE for everything else + return (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())); +} + +bool RlvActions::canStand(const LLUUID& idRlvObjExcept) +{ + // NOTE: must match generic function above + return (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_UNSIT, idRlvObjExcept)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())); +} + +// Checked: 2014-02-24 (RLVa-1.4.10) +bool RlvActions::canShowLocation() +{ + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); +} + +// ============================================================================ +// Helper functions +// + +template<> +const float& RlvActions::getModifierValue<float>(ERlvBehaviourModifier eBhvrMod) +{ + return RlvBehaviourDictionary::instance().getModifier(eBhvrMod)->getValue<float>(); +} + +// Checked: 2013-05-10 (RLVa-1.4.9) +bool RlvActions::hasBehaviour(ERlvBehaviour eBhvr) +{ + return gRlvHandler.hasBehaviour(eBhvr); +} + +// Checked: 2013-05-09 (RLVa-1.4.9) +bool RlvActions::hasOpenP2PSession(const LLUUID& idAgent) +{ + const LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent); + return (idSession.notNull()) && (LLIMMgr::instance().hasSession(idSession)); +} + +// Checked: 2013-05-09 (RLVa-1.4.9) +bool RlvActions::hasOpenGroupSession(const LLUUID& idGroup) +{ + return (idGroup.notNull()) && (LLIMMgr::instance().hasSession(idGroup)); +} + +// Checked: 2013-11-08 (RLVa-1.4.9) +bool RlvActions::isRlvEnabled() +{ + return RlvHandler::isEnabled(); +} + +void RlvActions::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs) +{ + RlvUtil::notifyBlocked(strNotifcation, sdArgs); +} + +// ============================================================================ diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h new file mode 100644 index 0000000000000000000000000000000000000000..90b1069f6bd27487233e6a058860efef9795b4df --- /dev/null +++ b/indra/newview/rlvactions.h @@ -0,0 +1,306 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_ACTIONS_H +#define RLV_ACTIONS_H + +#include "llchat.h" +#include "rlvdefines.h" + +// ============================================================================ +// Forward declarations +// + +class LLInventoryCategory; +class LLInventoryItem; + +// ============================================================================ +// RlvActions class declaration - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible +// + +class RlvActions +{ + // ====== + // Camera + // ====== +public: + /* + * Returns true if the specified object cannot manipulate the camera FOV + */ + static bool canChangeCameraFOV(const LLUUID& idRlvObject); + + /* + * Returns true if the specified object can manipulate the camera offset and/or focus offset values + */ + static bool canChangeCameraPreset(const LLUUID& idRlvObject); + + /* + * Returns true if the user can switch to mouselook + */ + static bool canChangeToMouselook(); + + /* + * Returns true if the camera's distance (from either the avatar of the focus) is currently restricted/clamped + */ + static bool isCameraDistanceClamped(); + + /* + * Returns true if the camera's FOV is currently restricted/clamped + */ + static bool isCameraFOVClamped(); + + /* + * Returns true if the camera offset and focus offset are locked (prevents changing the current camera preset) + */ + static bool isCameraPresetLocked(); + + /* + * Retrieves the current (avatar or focus) camera distance limits + */ + static bool getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax); + static bool getCameraOriginDistanceLimits(float& nDistMin, float& nDistMax); + + /* + * Retrieves the current camera FOV limits - returns isCameraFOVClamped() + */ + static bool getCameraFOVLimits(float& nFOVMin, float& nFOVMax); + + // ================================ + // Communication/Avatar interaction + // ================================ +public: + /* + * Returns true if the user is allowed to change their currently active group + */ + static bool canChangeActiveGroup(const LLUUID& idRlvObject = LLUUID::null); + + /* + * Returns true if the user is allowed to receive IMs from the specified sender (can be an avatar or a group) + */ + static bool canReceiveIM(const LLUUID& idSender); + + /* + * Returns true if the user is allowed to send/play gestures (whether active ones from the chat bar or using the gesture preview floater) + */ + static bool canPlayGestures(); + + /* + * Returns true if the user is allowed to chat on the specified channel + */ + static bool canSendChannel(int nChannel); + + /* + * Returns true if the user is allowed to send IMs to the specified recipient (can be an avatar or a group) + */ + static bool canSendIM(const LLUUID& idRecipient); + + /* + * Returns true if the user is allowed to start a - P2P or group - conversation with the specified UUID (or if the session already exists, unless 'ignore open' is specified) + */ + static bool canStartIM(const LLUUID& idRecipient, bool fIgnoreOpen = false); + + /* + * Returns true if an avatar's name should be hidden for the requested operation/context + * (This is used to hide an avatar name in one case but not a near-identical case - such as teleporting a friend vs a nearby agent - + * in a way that limits the amount of code that needs to be changed to carry context from one function to another) + */ + enum EShowNamesContext { SNC_DEFAULT = 0, SNC_NAMETAG, SNC_TELEPORTOFFER, SNC_TELEPORTREQUEST, SNC_COUNT }; + static bool canShowName(EShowNamesContext eContext, const LLUUID& idAgent = LLUUID::null); + static void setShowName(EShowNamesContext eContext, bool fCanShowName) { if ( (eContext < SNC_COUNT) && (isRlvEnabled()) ) { s_BlockNamesContexts[eContext] = !fCanShowName; } } + + /* + * Returns true if the user is allowed to see the presence of nearby avatars in UI elements (anonymized or otherwise) + */ + static bool canShowNearbyAgents(); + + /* + * Checks if the user is allowed to use the specified volume in (main) chat and returns the appropriate chat volume type + */ + static EChatType checkChatVolume(EChatType chatType); + +protected: + // Backwards logic so that we can initialize to 0 and it won't block when we forget to/don't check if RLVa is disabled + static bool s_BlockNamesContexts[SNC_COUNT]; + + // ========= + // Inventory + // ========= +public: + /* + * Returns true if the user is allowed to paste the specified inventory object (item/folder) into the specified destination category (within user inventory) + */ + static bool canPasteInventory(const LLInventoryCategory* pSourceCat, const LLInventoryCategory* pDestCat); + static bool canPasteInventory(const LLInventoryItem* pSourceItem, const LLInventoryCategory* pDestCat); + + /* + * Returns true if the user can open the inventory floater for (user/library/notecard/object)inventory based textures + */ + static bool canPreviewTextures(); + + // ======== + // Movement + // ======== +public: + /* + * Returns true if the user can accept an incoming teleport offer from the specified avatar + */ + static bool canAcceptTpOffer(const LLUUID& idSender); + + /* + * Returns true if a teleport offer from the specified avatar should be auto-accepted + * (pass the null UUID to check if all teleport offers should be auto-accepted regardless of sender) + */ + static bool autoAcceptTeleportOffer(const LLUUID& idSender); + + /* + * Returns true if the user can accept an incoming teleport request from the specified avatar + */ + static bool canAcceptTpRequest(const LLUUID& idSender); + + /* + * Returns true if a teleport request from the specified avatar should be auto-accepted + * (pass the null UUID to check if all teleport requests should be auto-accepted regardless of requester) + */ + static bool autoAcceptTeleportRequest(const LLUUID& idRequester); + + /* + * Returns true if the user can fly + * (NOTE: the parameter-less overload takes the currently executing command into account) + */ + static bool canFly(); + static bool canFly(const LLUUID& idRlvObjExcept); + + /* + * Returns true if the user can jump + */ + static bool canJump(); + + // =========== + // Teleporting + // =========== +public: + /* + * Returns true if the user can teleport locally (short distances) + */ + static bool canTeleportToLocal(const LLVector3d& posGlobal); + + /* + * Returns true if the user can teleport to a (remote) location + */ + static bool canTeleportToLocation(); + + /* + * Returns true if the teleport is considered local (e.g. double-click tp) + */ + static bool isLocalTp(const LLVector3d& posGlobal); + + // ================= + // World interaction + // ================= + // Terminology: + // - build : <todo> + // - edit : ability to get access an object from the build floater, or being able to look at its contents (i.e. open) + // - interact : ability to interact with an object/avatar in any way or shape (i.e. touch, edit, click, grab, move, ...) + // - rez : ability to rez new objects (from either inventory or through the create tool) + // - touch : singularly refers to the ability to either invoke the scripted touch handler, or perform a physical grab +public: + /* + * Returns true if the user can build (= access the build tools) + */ + static bool canBuild(); + + /* + * Returns true if the user can edit the specified object (with an optional relative offset) + */ + static bool canEdit(const LLViewerObject* pObj); + + /* + * Returns true if the user can sit on the ground + */ + static bool canGroundSit(); + + /* + * Returns true if the user can interact with the specified object (with an optional relative offset) + * (returns true if pObj == nullptr to not short circuit calling code) + */ + static bool canInteract(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero); + + /* + * Returns true if the user can rez new objects (from inventory or through the create tool) + */ + static bool canRez(); + + /* + * Returns true if the user can see the hovertext associated with the specified object + */ + static bool canShowHoverText(const LLViewerObject* pObj); + + /* + * Returns true if the user can sit on the specified object (see canGroundSit() for sitting on land) + */ + static bool canSit(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero); + + /* + * Returns true if the user can see their in-world location + */ + static bool canShowLocation(); + + /* + * Returns true if the user can stand up (returns true if the user isn't currently sitting) + */ + static bool canStand(); + static bool canStand(const LLUUID& idRlvObjExcept); + + /* + * Returns true if the user can touch the specified object (with an optional offset relative to its center) + */ + static bool canTouch(const LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero); + + // ================ + // Helper functions + // ================ +public: + /* + * Convenience function to get the current/active value of a behaviour modifier + */ + template<typename T> static const T& getModifierValue(ERlvBehaviourModifier eBhvrMod); + + /* + * Convenience function to check for a behaviour without having to include rlvhandler.h. + * Do NOT call this function if speed is important (i.e. per-frame) + */ + static bool hasBehaviour(ERlvBehaviour eBhvr); + + /* + * Returns true if a - P2P or group - IM session is open with the specified UUID + */ + static bool hasOpenP2PSession(const LLUUID& idAgent); + static bool hasOpenGroupSession(const LLUUID& idGroup); + + /* + * Convenience function to check if RLVa is enabled without having to include rlvhandler.h + */ + static bool isRlvEnabled(); + + /* + * Shows one of the blocked toast notifications (see rlva_strings.xml) + */ + static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD()); +}; + +// ============================================================================ + +#endif // RLV_ACTIONS_H diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2dad3a4d00123f9be09e85bab010c8a24f4a0d85 --- /dev/null +++ b/indra/newview/rlvcommon.cpp @@ -0,0 +1,912 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llagentui.h" +#include "llavatarnamecache.h" +#include "llcallingcard.h" +#include "llimview.h" +#include "llinstantmessage.h" +#include "llnotificationsutil.h" +#include "llregionhandle.h" +#include "llscriptruntimeperms.h" +#include "llsdserialize.h" +#include "lltrans.h" +#include "llversioninfo.h" +#include "llviewerparcelmgr.h" +#include "llviewermenu.h" +#include "llviewermessage.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llworld.h" + +#include "rlvactions.h" +#include "rlvcommon.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvlocks.h" + +#include <boost/algorithm/string.hpp> +#include <boost/regex.hpp> + + +// ============================================================================ +// Forward declarations +// + +// llviewermenu.cpp +LLVOAvatar* find_avatar_from_object(LLViewerObject* object); + +// ============================================================================ +// RlvNotifications +// + +// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b +/* +void RlvNotifications::warnGiveToRLV() +{ + if ( (gSavedSettings.getWarning(RLV_SETTING_FIRSTUSE_GIVETORLV)) && (RlvSettings::getForbidGiveToRLV()) ) + LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvNotifications::onGiveToRLVConfirmation); +} +*/ + +// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b +/* +void RlvNotifications::onGiveToRLVConfirmation(const LLSD& notification, const LLSD& response) +{ + gSavedSettings.setWarning(RLV_SETTING_FIRSTUSE_GIVETORLV, FALSE); + + S32 idxOption = LLNotification::getSelectedOption(notification, response); + if ( (0 == idxOption) || (1 == idxOption) ) + gSavedSettings.setBOOL(RLV_SETTING_FORBIDGIVETORLV, (idxOption == 1)); +} +*/ + +// ========================================================================= +// RlvSettings +// + +#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS +bool RlvSettings::s_fCompositeFolders = false; +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS +bool RlvSettings::s_fCanOOC = true; +U8 RlvSettings::s_nExperienceMinMaturity = 0; +bool RlvSettings::s_fLegacyNaming = true; +bool RlvSettings::s_fNoSetEnv = false; +bool RlvSettings::s_fTempAttach = true; +std::list<std::string> RlvSettings::s_BlockedExperiences; +std::list<LLUUID> RlvSettings::s_CompatItemCreators; +std::list<std::string> RlvSettings::s_CompatItemNames; + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0i +void RlvSettings::initClass() +{ + static bool fInitialized = false; + if (!fInitialized) + { + initCompatibilityMode(LLStringUtil::null); + + s_fTempAttach = rlvGetSetting<bool>(RLV_SETTING_ENABLETEMPATTACH, true); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLETEMPATTACH)) + gSavedSettings.getControl(RLV_SETTING_ENABLETEMPATTACH)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fTempAttach)); + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + s_fCompositeFolders = rlvGetSetting<bool>(RLV_SETTING_ENABLECOMPOSITES, false); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLECOMPOSITES)) + gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fCompositeFolders)); + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + s_fLegacyNaming = rlvGetSetting<bool>(RLV_SETTING_ENABLELEGACYNAMING, true); + if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) + gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &s_fLegacyNaming)); + + s_fCanOOC = rlvGetSetting<bool>(RLV_SETTING_CANOOC, true); + s_fNoSetEnv = rlvGetSetting<bool>(RLV_SETTING_NOSETENV, false); + + // Don't allow toggling RLVaLoginLastLocation from the debug settings floater + if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) + gSavedPerAccountSettings.getControl(RLV_SETTING_LOGINLASTLOCATION)->setHiddenFromSettingsEditor(true); + + if (gSavedSettings.controlExists(RLV_SETTING_TOPLEVELMENU)) + gSavedSettings.getControl(RLV_SETTING_TOPLEVELMENU)->getSignal()->connect(boost::bind(&onChangedMenuLevel)); + + int nMinMaturity = gSavedSettings.getS32("RLVaExperienceMaturityThreshold"); + s_nExperienceMinMaturity = (nMinMaturity == 0) ? 0 : ((nMinMaturity == 1) ? SIM_ACCESS_PG : ((nMinMaturity == 2) ? SIM_ACCESS_MATURE : SIM_ACCESS_ADULT)); + const std::string& strBlockedExperiences = gSavedSettings.getString("RLVaBlockedExperiences"); + boost::split(s_BlockedExperiences, strBlockedExperiences, boost::is_any_of(";")); + + fInitialized = true; + } +} + +// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d +void RlvSettings::updateLoginLastLocation() +{ + if ( (!LLApp::isQuitting()) && (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) ) + { + BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand()); + if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) + { + gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); + gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); + } + } +} + +// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b +bool RlvSettings::onChangedMenuLevel() +{ + rlvMenuToggleVisible(); + return true; +} + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0i +bool RlvSettings::onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting) +{ + if (pfSetting) + *pfSetting = sdValue.asBoolean(); + return true; +} + +void RlvSettings::onChangedSettingMain(const LLSD& sdValue) +{ + LLStringUtil::format_map_t args; + args["[STATE]"] = LLTrans::getString( (sdValue.asBoolean()) ? "RLVaToggleEnabled" : "RLVaToggleDisabled"); + + // As long as RLVa hasn't been enabled but >can< be enabled all toggles are instant (everything else will require a restart) + bool fQuickToggle = (!RlvHandler::isEnabled()) && (RlvHandler::canEnable()); + LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", LLTrans::getString((fQuickToggle) ? "RLVaToggleMessageLogin" : "RLVaToggleMessageRestart", args))); +} + +void RlvSettings::initCompatibilityMode(std::string strCompatList) +{ + // NOTE: this function can be called more than once + s_CompatItemCreators.clear(); + s_CompatItemNames.clear(); + + strCompatList.append(";").append(rlvGetSetting<std::string>("RLVaCompatibilityModeList", "")); + + boost_tokenizer tokCompatList(strCompatList, boost::char_separator<char>(";", "", boost::drop_empty_tokens)); + for (const std::string& strCompatEntry : tokCompatList) + { + if (boost::starts_with(strCompatEntry, "creator:")) + { + LLUUID idCreator; + if ( (44 == strCompatEntry.size()) && (LLUUID::parseUUID(strCompatEntry.substr(8), &idCreator)) && + (s_CompatItemCreators.end() == std::find(s_CompatItemCreators.begin(), s_CompatItemCreators.end(), idCreator)) ) + { + s_CompatItemCreators.push_back(idCreator); + } + } + else if (boost::starts_with(strCompatEntry, "name:")) + { + if (strCompatEntry.size() > 5) + s_CompatItemNames.push_back(strCompatEntry.substr(5)); + } + } +} + +bool RlvSettings::isCompatibilityModeObject(const LLUUID& idRlvObject) +{ + bool fCompatMode = false; + if (idRlvObject.notNull()) + { + const LLViewerObject* pObj = gObjectList.findObject(idRlvObject); + if ( (pObj) && (pObj->isAttachment()) ) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(pObj->getAttachmentItemID()); + if (pItem) + { + fCompatMode = s_CompatItemCreators.end() != std::find(s_CompatItemCreators.begin(), s_CompatItemCreators.end(), pItem->getCreatorUUID()); + if (!fCompatMode) + { + const std::string& strAttachName = pItem->getName(); + for (const std::string& strCompatName : s_CompatItemNames) + { + boost::regex regexp(strCompatName, boost::regex::perl | boost::regex::icase); + if (boost::regex_match(strAttachName, regexp)) + { + fCompatMode = true; + break; + } + } + } + } + } + } + return fCompatMode; +} + +bool RlvSettings::isAllowedExperience(const LLUUID& idExperience, U8 nMaturity) +{ + // An experience is allowed to interact with RLVa if: + // - temporary attachments can interact with RLVa + // - the user set a minimum maturity and the specified maturity is equal or higher + // - the experience isn't explicitly blocked (NOTE: case-sensitive string comparison) + return + (getEnableTemporaryAttachments()) && + (s_nExperienceMinMaturity) && (s_nExperienceMinMaturity <= nMaturity) && + (s_BlockedExperiences.end() == std::find(s_BlockedExperiences.begin(), s_BlockedExperiences.end(), idExperience.asString())); +} + +// ============================================================================ +// RlvStrings +// + +std::vector<std::string> RlvStrings::m_Anonyms; +RlvStrings::string_map_t RlvStrings::m_StringMap; +std::string RlvStrings::m_StringMapPath; + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::initClass() +{ + static bool fInitialized = false; + if (!fInitialized) + { + // Load the default string values + std::vector<std::string> files = gDirUtilp->findSkinnedFilenames(LLDir::XUI, RLV_STRINGS_FILE, LLDir::ALL_SKINS); + m_StringMapPath = (!files.empty()) ? files.front() : LLStringUtil::null; + for (std::vector<std::string>::const_iterator itFile = files.begin(); itFile != files.end(); ++itFile) + { + loadFromFile(*itFile, false); + } + + // Load the custom string overrides + loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE), true); + + // Sanity check + if ( (m_StringMap.empty()) || (m_Anonyms.empty()) ) + { + RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL; + return; + } + + fInitialized = true; + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::loadFromFile(const std::string& strFilePath, bool fUserOverride) +{ + llifstream fileStream(strFilePath.c_str(), std::ios::binary); LLSD sdFileData; + if ( (!fileStream.is_open()) || (!LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) ) + return; + fileStream.close(); + + if (sdFileData.has("strings")) + { + const LLSD& sdStrings = sdFileData["strings"]; + for (LLSD::map_const_iterator itString = sdStrings.beginMap(); itString != sdStrings.endMap(); ++itString) + { + if ( (!itString->second.has("value")) || ((fUserOverride) && (!hasString(itString->first))) ) + continue; + + std::list<std::string>& listValues = m_StringMap[itString->first]; + if (!fUserOverride) + { + if (listValues.size() > 0) + listValues.pop_front(); + listValues.push_front(itString->second["value"].asString()); + } + else + { + while (listValues.size() > 1) + listValues.pop_back(); + listValues.push_back(itString->second["value"].asString()); + } + } + } + if (sdFileData.has("anonyms")) + { + const LLSD& sdAnonyms = sdFileData["anonyms"]; + for (LLSD::array_const_iterator itAnonym = sdAnonyms.beginArray(); itAnonym != sdAnonyms.endArray(); ++itAnonym) + { + m_Anonyms.push_back((*itAnonym).asString()); + } + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::saveToFile(const std::string& strFilePath) +{ + LLSD sdFileData; + + LLSD& sdStrings = sdFileData["strings"]; + for (string_map_t::const_iterator itString = m_StringMap.begin(); itString != m_StringMap.end(); ++itString) + { + const std::list<std::string>& listValues = itString->second; + if (listValues.size() > 1) + sdStrings[itString->first]["value"] = listValues.back(); + } + + llofstream fileStream(strFilePath.c_str()); + if (!fileStream.good()) + return; + + LLSDSerialize::toPrettyXML(sdFileData, fileStream); + fileStream.close(); +} + +// Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a +const std::string& RlvStrings::getAnonym(const std::string& strName) +{ + static const std::string strUnknown = LLTrans::getString("Unknown"); + if ( (!RlvActions::isRlvEnabled()) || (m_Anonyms.empty()) ) + { + return strUnknown; + } + + const char* pszName = strName.c_str(); U32 nHash = 0; + + // Test with 11,264 SL names showed a 3.33% - 3.82% occurance for each so we *should* get a very even spread + for (int idx = 0, cnt = strName.length(); idx < cnt; idx++) + nHash += pszName[idx]; + + return m_Anonyms[nHash % m_Anonyms.size()]; +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +const std::string& RlvStrings::getString(const std::string& strStringName) +{ + static const std::string strMissing = "(Missing RLVa string)"; + string_map_t::const_iterator itString = m_StringMap.find(strStringName); + return (itString != m_StringMap.end()) ? itString->second.back() : strMissing; +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Added: RLVa-1.1.0f +const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet) +{ + // TODO-RLVa: [2009-11-25] clean this up along with the calling code in process_chat_from_simulator() once we're happy with the output + switch (eRet) + { + case RLV_RET_SUCCESS_UNSET: + return "unset"; + case RLV_RET_SUCCESS_DUPLICATE: + return "duplicate"; + case RLV_RET_SUCCESS_DELAYED: + return "delayed"; + case RLV_RET_SUCCESS_DEPRECATED: + return "deprecated"; + case RLV_RET_FAILED_SYNTAX: + return "thingy error"; + case RLV_RET_FAILED_OPTION: + return "invalid option"; + case RLV_RET_FAILED_PARAM: + return "invalid param"; + case RLV_RET_FAILED_LOCK: + return "locked command"; + case RLV_RET_FAILED_DISABLED: + return "disabled command"; + case RLV_RET_FAILED_UNKNOWN: + return "unknown command"; + case RLV_RET_FAILED_NOSHAREDROOT: + return "missing #RLV"; + case RLV_RET_FAILED_DEPRECATED: + return "deprecated and disabled"; + case RLV_RET_FAILED_NOBEHAVIOUR: + return "no active behaviours"; + case RLV_RET_FAILED_BLOCKED: + return "blocked object"; + case RLV_RET_FAILED_THROTTLED: + return "throttled"; + // The following are identified by the chat verb + case RLV_RET_RETAINED: + case RLV_RET_SUCCESS: + case RLV_RET_FAILED: + break; + // The following shouldn't occur + case RLV_RET_UNKNOWN: + default: + RLV_ASSERT(false); + break; + }; + return NULL; +} + +std::string RlvStrings::getVersion(const LLUUID& idRlvObject, bool fLegacy) +{ + bool fCompatMode = RlvSettings::isCompatibilityModeObject(idRlvObject); + return llformat("%s viewer v%d.%d.%d (RLVa %d.%d.%d)", + ( (!fLegacy) ? "RestrainedLove" : "RestrainedLife" ), + (!fCompatMode) ? RLV_VERSION_MAJOR : RLV_VERSION_MAJOR_COMPAT, (!fCompatMode) ? RLV_VERSION_MINOR : RLV_VERSION_MINOR_COMPAT, (!fCompatMode) ? RLV_VERSION_PATCH : RLV_VERSION_PATCH_COMPAT, + RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH); +} + +std::string RlvStrings::getVersionAbout() +{ + return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d.%d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, LLVersionInfo::getBuild()); +} + +std::string RlvStrings::getVersionNum(const LLUUID& idRlvObject) +{ + bool fCompatMode = RlvSettings::isCompatibilityModeObject(idRlvObject); + return llformat("%d%02d%02d%02d", + (!fCompatMode) ? RLV_VERSION_MAJOR : RLV_VERSION_MAJOR_COMPAT, (!fCompatMode) ? RLV_VERSION_MINOR : RLV_VERSION_MINOR_COMPAT, + (!fCompatMode) ? RLV_VERSION_PATCH : RLV_VERSION_PATCH_COMPAT, (!fCompatMode) ? RLV_VERSION_BUILD : RLV_VERSION_BUILD_COMPAT); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +bool RlvStrings::hasString(const std::string& strStringName, bool fCheckCustom) +{ + string_map_t::const_iterator itString = m_StringMap.find(strStringName); + return (itString != m_StringMap.end()) && ((!fCheckCustom) || (itString->second.size() > 0)); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::setCustomString(const std::string& strStringName, const std::string& strStringValue) +{ + if (!hasString(strStringName)) + return; + + std::list<std::string>& listValues = m_StringMap[strStringName]; + while (listValues.size() > 1) + listValues.pop_back(); + if (!strStringValue.empty()) + listValues.push_back(strStringValue); +} + +// ============================================================================ +// RlvUtil +// + +bool RlvUtil::m_fForceTp = false; + +// Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a +void RlvUtil::filterLocation(std::string& strUTF8Text) +{ + // Filter any mention of the surrounding region names + LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList(); + const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion) + boost::ireplace_all(strUTF8Text, (*itRegion)->getName(), strHiddenRegion); + + // Filter any mention of the parcel name + LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance(); + if (pParcelMgr) + boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL)); +} + +// Checked: 2010-12-08 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c +void RlvUtil::filterNames(std::string& strUTF8Text, bool fFilterLegacy, bool fClearMatches) +{ + uuid_vec_t idAgents; + LLWorld::getInstance()->getAvatars(&idAgents, NULL); + for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) + { + LLAvatarName avName; + // NOTE: if we're agressively culling nearby names then ignore exceptions + if ( (LLAvatarNameCache::get(idAgents[idxAgent], &avName)) && ((fClearMatches) || (!RlvActions::canShowName(RlvActions::SNC_DEFAULT, idAgents[idxAgent]))) ) + { + const std::string& strDisplayName = avName.getDisplayName(); + bool fFilterDisplay = (strDisplayName.length() > 2); + const std::string& strLegacyName = avName.getLegacyName(); + fFilterLegacy &= (strLegacyName.length() > 2); + const std::string& strAnonym = (!fClearMatches) ? RlvStrings::getAnonym(avName) : LLStringUtil::null; + + // If the display name is a subset of the legacy name we need to filter that first, otherwise it's the other way around + if (boost::icontains(strLegacyName, strDisplayName)) + { + if (fFilterLegacy) + boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym); + if (fFilterDisplay) + boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym); + } + else + { + if (fFilterDisplay) + boost::ireplace_all(strUTF8Text, strDisplayName, strAnonym); + if (fFilterLegacy) + boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym); + } + } + } +} + +// Checked: 2012-08-19 (RLVa-1.4.7) +void RlvUtil::filterScriptQuestions(S32& nQuestions, LLSD& sdPayload) +{ + // Check SCRIPT_PERMISSION_ATTACH + if ((!gRlvAttachmentLocks.canAttach()) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit & nQuestions)) + { + // Notify the user that we blocked it since they're not allowed to wear any new attachments + sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMATTACH; + nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_ATTACH].permbit; + } + + // Check SCRIPT_PERMISSION_TELEPORT + if ((gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) && (SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit & nQuestions)) + { + // Notify the user that we blocked it since they're not allowed to teleport + sdPayload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMTELEPORT; + nQuestions &= ~SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_TELEPORT].permbit; + } + + sdPayload["questions"] = nQuestions; +} + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +void RlvUtil::forceTp(const LLVector3d& posDest) +{ + m_fForceTp = true; + gAgent.teleportViaLocationLookAt(posDest); + m_fForceTp = false; +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +bool RlvUtil::isNearbyAgent(const LLUUID& idAgent) +{ + // Sanity check since we call this with notification payloads as well and those strings tend to change from one release to another + RLV_ASSERT(idAgent.notNull()); + if ( (idAgent.notNull()) && (gAgent.getID() != idAgent) ) + { + std::vector<LLUUID> idAgents; + LLWorld::getInstance()->getAvatars(&idAgents, NULL); + + for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) + if (idAgents[idxAgent] == idAgent) + return true; + } + return false; +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +bool RlvUtil::isNearbyRegion(const std::string& strRegion) +{ + LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList(); + for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion) + if ((*itRegion)->getName() == strRegion) + return true; + return false; +} + +// Checked: 2011-04-11 (RLVa-1.3.0h) | Modified: RLVa-1.3.0h +void RlvUtil::notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs, bool fLogToChat) +{ + std::string strMsg = RlvStrings::getString(strNotifcation); + LLStringUtil::format(strMsg, sdArgs); + + LLSD sdNotify; + sdNotify["MESSAGE"] = strMsg; + if (!fLogToChat) + LLNotificationsUtil::add("SystemMessageTip", sdNotify); + else + LLNotificationsUtil::add("ChatSystemMessageTip", sdNotify); +} + +// Checked: 2010-11-11 (RLVa-1.2.1g) | Added: RLVa-1.2.1g +void RlvUtil::notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine) +{ + // Don't show the same assertion over and over, or if the user opted out + static std::string strAssertPrev, strFilePrev; static int nLinePrev; + if ( ((strAssertPrev == strAssert) && (strFile == strFilePrev) && (nLine == nLinePrev)) || + (!rlvGetSetting<bool>(RLV_SETTING_SHOWASSERTIONFAIL, true)) ) + { + return; + } + + strAssertPrev = strAssert; + strFilePrev = strFile; + nLinePrev = nLine; + + LLSD argsNotify; + argsNotify["MESSAGE"] = llformat("RLVa assertion failure: %s (%s - %d)", strAssert.c_str(), strFile.c_str(), nLine); + LLNotificationsUtil::add("SystemMessageTip", argsNotify); +} + +// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b +void RlvUtil::sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession) +{ + // [See process_improved_im()] + std::string strFullName; + LLAgentUI::buildFullname(strFullName); + + pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName, + strMsg, IM_ONLINE, IM_DO_NOT_DISTURB_AUTO_RESPONSE, idSession); + gAgent.sendReliableMessage(); +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.0.1e +bool RlvUtil::sendChatReply(S32 nChannel, const std::string& strUTF8Text) +{ + if (!isValidReplyChannel(nChannel)) + return false; + + // Copy/paste from send_chat_from_viewer() + gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ChatData); + gMessageSystem->addStringFast(_PREHASH_Message, utf8str_truncate(strUTF8Text, MAX_MSG_STR_LEN)); + gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT); + gMessageSystem->addS32("Channel", nChannel); + gAgent.sendReliableMessage(); + add(LLStatViewer::CHAT_COUNT, 1); + + return true; +} + +bool RlvUtil::sendChatReplySplit(S32 nChannel, const std::string& strMsg, char chSplit) +{ + std::list<std::string> msgList; + utf8str_split(msgList, strMsg, MAX_MSG_STR_LEN, chSplit); + for (const std::string& strMsg : msgList) + { + if (!sendChatReply(nChannel, strMsg)) + { + return false; + } + } + return true; +} + +void RlvUtil::sendIMMessage(const LLUUID& idRecipient, const std::string& strMsg, char chSplit) +{ + const LLUUID idSession = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, idRecipient); + const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idRecipient); + std::string strAgentName; + LLAgentUI::buildFullname(strAgentName); + + std::list<std::string> msgList; + utf8str_split(msgList, strMsg, MAX_MSG_STR_LEN, chSplit); + for (const std::string& strMsg : msgList) + { + pack_instant_message( + gMessageSystem, + gAgent.getID(), + false, + gAgent.getSessionID(), + idRecipient, + strAgentName.c_str(), + strMsg.c_str(), + ((!pBuddyInfo) || (pBuddyInfo->isOnline())) ? IM_ONLINE : IM_OFFLINE, + IM_NOTHING_SPECIAL, + idSession); + gAgent.sendReliableMessage(); + } +} + +// ============================================================================ +// Generic menu enablers +// + +// Checked: 2015-05-25 (RLVa-1.5.0) +bool rlvMenuMainToggleVisible(LLUICtrl* pMenuCtrl) +{ + LLMenuItemCheckGL* pMenuItem = dynamic_cast<LLMenuItemCheckGL*>(pMenuCtrl); + if (pMenuItem) + { + static std::string strLabel = pMenuItem->getLabel(); + if ((bool)gSavedSettings.getBOOL(RLV_SETTING_MAIN) == rlv_handler_t::isEnabled()) + pMenuItem->setLabel(strLabel); + else + pMenuItem->setLabel(strLabel + " " + LLTrans::getString("RLVaPendingRestart")); + } + return true; +} + +// Checked: 2011-08-16 (RLVa-1.4.0b) | Added: RLVa-1.4.0b +void rlvMenuToggleVisible() +{ + bool fTopLevel = rlvGetSetting(RLV_SETTING_TOPLEVELMENU, true); + bool fRlvEnabled = rlv_handler_t::isEnabled(); + + LLMenuGL* pRLVaMenuMain = gMenuBarView->findChildMenuByName("RLVa Main", FALSE); + LLMenuGL* pAdvancedMenu = gMenuBarView->findChildMenuByName("Advanced", FALSE); + LLMenuGL* pRLVaMenuEmbed = pAdvancedMenu->findChildMenuByName("RLVa Embedded", FALSE); + + gMenuBarView->setItemVisible("RLVa Main", (fRlvEnabled) && (fTopLevel)); + pAdvancedMenu->setItemVisible("RLVa Embedded", (fRlvEnabled) && (!fTopLevel)); + + if ( (rlv_handler_t::isEnabled()) && (pRLVaMenuMain) && (pRLVaMenuEmbed) && + ( ((fTopLevel) && (1 == pRLVaMenuMain->getItemCount())) || ((!fTopLevel) && (1 == pRLVaMenuEmbed->getItemCount())) ) ) + { + LLMenuGL* pMenuFrom = (fTopLevel) ? pRLVaMenuEmbed : pRLVaMenuMain; + LLMenuGL* pMenuTo = (fTopLevel) ? pRLVaMenuMain : pRLVaMenuEmbed; + while (LLMenuItemGL* pItem = pMenuFrom->getItem(1)) + { + pMenuFrom->removeChild(pItem); + pMenuTo->addChild(pItem); + pItem->updateBranchParent(pMenuTo); + } + } +} + +bool rlvMenuCanShowName() +{ + const LLVOAvatar* pAvatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + return (pAvatar) && (RlvActions::canShowName(RlvActions::SNC_DEFAULT, pAvatar->getID())); +} + +// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +bool rlvMenuEnableIfNot(const LLSD& sdParam) +{ + bool fEnable = true; + if (rlv_handler_t::isEnabled()) + { + ERlvBehaviour eBhvr = RlvBehaviourDictionary::instance().getBehaviourFromString(sdParam.asString(), RLV_TYPE_ADDREM); + fEnable = (eBhvr != RLV_BHVR_UNKNOWN) ? !gRlvHandler.hasBehaviour(eBhvr) : true; + } + return fEnable; +} + +// ============================================================================ +// Selection functors +// + +// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0 +bool rlvCanDeleteOrReturn(const LLViewerObject* pObj) +{ + // Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || ((!pObj->permYouOwner()) && (!pObj->permGroupOwner())) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (!isAgentAvatarValid()) || (!pObj->getRootEdit()->isChild(gAgentAvatarp)) ); +} + +// Checked: 2011-05-28 (RLVa-1.4.6) | Modified: RLVa-1.4.0 +bool rlvCanDeleteOrReturn() +{ + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) ) + { + struct RlvCanDeleteOrReturn : public LLSelectedObjectFunctor + { + /*virtual*/ bool apply(LLViewerObject* pObj) { return rlvCanDeleteOrReturn(pObj); } + } f; + LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); + return (hSel.notNull()) && (0 != hSel->getRootObjectCount()) && (hSel->applyToRootObjects(&f, false)); + } + return true; +} + +// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-0.2.0f +bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode) +{ + return (pNode->getObject()) ? gRlvAttachmentLocks.isLockedAttachment(pNode->getObject()->getRootEdit()) : false; +} + +// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c +bool RlvSelectIsEditable::apply(LLSelectNode* pNode) +{ + const LLViewerObject* pObj = pNode->getObject(); + return (pObj) && (!RlvActions::canEdit(pObj)); +} + +// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode) +{ + return (pNode->getObject()) && (pNode->getObject()->getRootEdit()->isChild(m_pAvatar)); +} + +// ============================================================================ +// Predicates +// + +// Checked: 2010-11-11 (RLVa-1.2.1g) | Modified: RLVa-1.2.1g +bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask) +{ + if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) ) + { + if (RlvForceWear::isWearingItem(pItem)) + return true; // Special exception for currently worn items + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + // NOTE: only one body part of each type is allowed so the only way to wear one is if we can replace the current one + return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & RLV_WEAR_REPLACE & eWearMask)); + case LLAssetType::AT_CLOTHING: + return (RLV_WEAR_LOCKED != (gRlvWearableLocks.canWear(pItem) & eWearMask)); + case LLAssetType::AT_OBJECT: + return (RLV_WEAR_LOCKED != (gRlvAttachmentLocks.canAttach(pItem) & eWearMask)); + case LLAssetType::AT_GESTURE: + return true; + default: + RLV_ASSERT(false); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask) +{ + return !rlvPredCanWearItem(pItem, eWearMask); +} + +// Checked: 2014-11-02 (RLVa-1.4.11) +bool rlvPredCanRemoveItem(const LLUUID& idItem) +{ + // Check the inventory item if it's available + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + if (pItem) + { + return rlvPredCanRemoveItem(pItem); + } + + // Temporary attachments don't have inventory items associated with them so check the attachment itself + if (isAgentAvatarValid()) + { + const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(idItem); + return (pAttachObj) && (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj)); + } + + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0) +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem) +{ + if (pItem) + { + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gRlvWearableLocks.canRemove(pItem); + case LLAssetType::AT_OBJECT: + return gRlvAttachmentLocks.canDetach(pItem); + case LLAssetType::AT_GESTURE: + return true; + case LLAssetType::AT_LINK: + case LLAssetType::AT_LINK_FOLDER: + // Broken links can always be removed since they don't represent a worn item + return true; + default: + RLV_ASSERT(!RlvForceWear::isWearableItem(pItem)); + } + } + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem) +{ + return !rlvPredCanRemoveItem(pItem); +} + +// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +RlvPredIsEqualOrLinkedItem::RlvPredIsEqualOrLinkedItem(const LLUUID& idItem) +{ + m_pItem = gInventory.getItem(idItem); +} + +// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +bool RlvPredIsEqualOrLinkedItem::operator()(const LLViewerInventoryItem* pItem) const +{ + return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID()); +} + +// ============================================================================ +// Various public helper functions +// + +// Checked: 2009-11-15 (RLVa-1.1.0c) | Added: RLVa-1.1.0c +/* +BOOL rlvEnableSharedWearEnabler(void* pParam) +{ + return false; + // Visually disable the "Enable Shared Wear" option when at least one attachment is non-detachable + return (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE)); +} +*/ + +// Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +const std::string& rlvGetAnonym(const LLAvatarName& avName) +{ + return RlvStrings::getAnonym(avName); +} + +// ============================================================================ diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h new file mode 100644 index 0000000000000000000000000000000000000000..47a8ebf1483cf92c87d1e554b06ef102eb01572b --- /dev/null +++ b/indra/newview/rlvcommon.h @@ -0,0 +1,335 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_COMMON_H +#define RLV_COMMON_H + +#include "llavatarname.h" +#include "llselectmgr.h" +#include "llviewercontrol.h" + +#include "rlvdefines.h" + +#ifdef LL_WINDOWS + #pragma warning (push) + #pragma warning (disable : 4702) // warning C4702: unreachable code +#endif +#include <boost/variant.hpp> +#ifdef LL_WINDOWS + #pragma warning (pop) +#endif + +// ============================================================================ +// Forward declarations +// + +// +// General viewer source +// +class LLInventoryItem; +class LLUICtrl; +class LLViewerInventoryCategory; +class LLViewerInventoryItem; +class LLViewerJointAttachment; +class LLViewerWearable; +class LLWearable; + +// +// RLVa-specific +// +class RlvCommand; +typedef std::list<RlvCommand> rlv_command_list_t; +class RlvObject; + +struct RlvException; +typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption; +typedef boost::variant<int, float, bool, LLVector3, LLUUID> RlvBehaviourModifierValue; + +class RlvGCTimer; + +// ============================================================================ +// RlvSettings +// + +template<typename T> inline T rlvGetSetting(const std::string& strSetting, const T& defaultValue) +{ + RLV_ASSERT_DBG(gSavedSettings.controlExists(strSetting)); + return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.get<T>(strSetting) : defaultValue; +} + +template<typename T> inline T rlvGetPerUserSetting(const std::string& strSetting, const T& defaultValue) +{ + RLV_ASSERT_DBG(gSavedPerAccountSettings.controlExists(strSetting)); + return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.get<T>(strSetting) : defaultValue; +} + +class RlvSettings +{ +public: + static bool getDebug() { return rlvGetSetting<bool>(RLV_SETTING_DEBUG, false); } + static bool getCanOOC() { return s_fCanOOC; } + static bool getForbidGiveToRLV() { return rlvGetSetting<bool>(RLV_SETTING_FORBIDGIVETORLV, true); } + static bool getNoSetEnv() { return s_fNoSetEnv; } + + static std::string getWearAddPrefix() { return rlvGetSetting<std::string>(RLV_SETTING_WEARADDPREFIX, LLStringUtil::null); } + static std::string getWearReplacePrefix() { return rlvGetSetting<std::string>(RLV_SETTING_WEARREPLACEPREFIX, LLStringUtil::null); } + + static bool getDebugHideUnsetDup() { return rlvGetSetting<bool>(RLV_SETTING_DEBUGHIDEUNSETDUP, false); } + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL getEnableComposites() { return s_fCompositeFolders; } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static bool getEnableIMQuery() { return rlvGetSetting<bool>("RLVaEnableIMQuery", true); } + static bool getEnableLegacyNaming() { return s_fLegacyNaming; } + static bool getEnableSharedWear() { return rlvGetSetting<bool>(RLV_SETTING_ENABLESHAREDWEAR, false); } + static bool getEnableTemporaryAttachments() { return s_fTempAttach; } + static bool getHideLockedLayers() { return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDLAYER, false); } + static bool getHideLockedAttach() { return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDATTACH, false); } + static bool getHideLockedInventory() { return rlvGetSetting<bool>(RLV_SETTING_HIDELOCKEDINVENTORY, false); } + static bool getSharedInvAutoRename() { return rlvGetSetting<bool>(RLV_SETTING_SHAREDINVAUTORENAME, true); } + static bool getSplitRedirectChat() { return rlvGetSetting<bool>(RLV_SETTING_SPLITREDIRECTCHAT, false); } + + static bool getLoginLastLocation() { return rlvGetPerUserSetting<bool>(RLV_SETTING_LOGINLASTLOCATION, true); } + static void updateLoginLastLocation(); + + static void initCompatibilityMode(std::string strCompatList); + static bool isCompatibilityModeObject(const LLUUID& idRlvObject); + + static bool isAllowedExperience(const LLUUID& idExperience, U8 nMaturity); + + static void initClass(); + static void onChangedSettingMain(const LLSD& sdValue); +protected: + static bool onChangedMenuLevel(); + static bool onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting); + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + static BOOL s_fCompositeFolders; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + /* + * Member variables + */ +protected: + static bool s_fCanOOC; + static U8 s_nExperienceMinMaturity; + static bool s_fLegacyNaming; + static bool s_fNoSetEnv; + static bool s_fTempAttach; + static std::list<std::string> s_BlockedExperiences; + static std::list<LLUUID> s_CompatItemCreators; + static std::list<std::string> s_CompatItemNames; +}; + +// ============================================================================ +// RlvStrings +// + +class RlvStrings +{ +public: + static void initClass(); + static void loadFromFile(const std::string& strFilePath, bool fDefault); + static void saveToFile(const std::string& strFilePath); + + static const std::string& getAnonym(const LLAvatarName& avName); // @shownames + static const std::string& getAnonym(const std::string& strName); // @shownames + static const std::string& getString(const std::string& strStringName); + static const char* getStringFromReturnCode(ERlvCmdRet eRet); + static const std::string& getStringMapPath() { return m_StringMapPath; } + static std::string getVersion(const LLUUID& idRlvObject, bool fLegacy = false); + static std::string getVersionAbout(); + static std::string getVersionNum(const LLUUID& idRlvObject); + static bool hasString(const std::string& strStringName, bool fCheckCustom = false); + static void setCustomString(const std::string& strStringName, const std::string& strStringValue); + +protected: + static std::vector<std::string> m_Anonyms; + typedef std::map<std::string, std::list<std::string> > string_map_t; + static string_map_t m_StringMap; + static std::string m_StringMapPath; +}; + +// ============================================================================ +// RlvUtil - Collection of (static) helper functions +// + +class RlvUtil +{ +public: + static bool isEmote(const std::string& strUTF8Text); + static bool isNearbyAgent(const LLUUID& idAgent); // @shownames + static bool isNearbyRegion(const std::string& strRegion); // @showloc + + static void filterLocation(std::string& strUTF8Text); // @showloc + static void filterNames(std::string& strUTF8Text, bool fFilterLegacy = true, bool fClearMatches = false); // @shownames + static void filterScriptQuestions(S32& nQuestions, LLSD& sdPayload); + + static bool isForceTp() { return m_fForceTp; } + static void forceTp(const LLVector3d& posDest); // Ignores restrictions that might otherwise prevent tp'ing + + static void notifyBlocked(const std::string& strNotifcation, const LLSD& sdArgs = LLSD(), bool fLogToChat = false); + static void notifyBlockedGeneric() { notifyBlocked(RLV_STRING_BLOCKED_GENERIC); } + static void notifyBlockedViewXXX(LLAssetType::EType assetType) { notifyBlocked(RLV_STRING_BLOCKED_VIEWXXX, LLSD().with("[TYPE]", LLAssetType::lookup(assetType))); } + static void notifyFailedAssertion(const std::string& strAssert, const std::string& strFile, int nLine); + + static void sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null); + static bool isValidReplyChannel(S32 nChannel, bool fLoopback = false); + static bool sendChatReply(S32 nChannel, const std::string& strUTF8Text); + static bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text); + static bool sendChatReplySplit(S32 nChannel, const std::string& strUTF8Text, char chSplit = ' '); + static void sendIMMessage(const LLUUID& idTo, const std::string& strMsg, char chSplit); +protected: + static bool m_fForceTp; // @standtp +}; + +// ============================================================================ +// Extensibility classes +// + +class RlvExtCommandHandler +{ +public: + virtual ~RlvExtCommandHandler() {} + virtual bool onAddRemCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onClearCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } + virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; } +}; +typedef bool (RlvExtCommandHandler::*rlvExtCommandHandler)(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); + +// ============================================================================ +// Generic menu enablers +// + +bool rlvMenuMainToggleVisible(LLUICtrl* pMenuItem); +void rlvMenuToggleVisible(); +bool rlvMenuCanShowName(); +bool rlvMenuEnableIfNot(const LLSD& sdParam); + +// ============================================================================ +// Selection functors +// + +bool rlvCanDeleteOrReturn(); +bool rlvCanDeleteOrReturn(const LLViewerObject* pObj); + +struct RlvSelectHasLockedAttach : public LLSelectedNodeFunctor +{ + RlvSelectHasLockedAttach() {} + virtual bool apply(LLSelectNode* pNode); +}; + +// Filters out selected objects that can't be editable (i.e. getFirstNode() will return NULL if the selection is fully editable) +struct RlvSelectIsEditable : public LLSelectedNodeFunctor +{ + RlvSelectIsEditable() {} + /*virtual*/ bool apply(LLSelectNode* pNode); +}; + +struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor +{ + RlvSelectIsSittingOn(const LLVOAvatar* pAvatar) : m_pAvatar(pAvatar) {} + /*virtual*/ bool apply(LLSelectNode* pNode); +protected: + const LLVOAvatar* m_pAvatar; +}; + +// ============================================================================ +// Predicates +// + +bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); +bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); +bool rlvPredCanRemoveItem(const LLUUID& idItem); +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem); +bool rlvPredCanNotRemoveItem(const LLUUID& idItem); +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem); + +struct RlvPredCanWearItem +{ + RlvPredCanWearItem(ERlvWearMask eWearMask) : m_eWearMask(eWearMask) {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanWearItem(pItem, m_eWearMask); } +protected: + ERlvWearMask m_eWearMask; +}; + +struct RlvPredCanNotWearItem +{ + RlvPredCanNotWearItem(ERlvWearMask eWearMask) : m_eWearMask(eWearMask) {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotWearItem(pItem, m_eWearMask); } +protected: + ERlvWearMask m_eWearMask; +}; + +struct RlvPredCanRemoveItem +{ + RlvPredCanRemoveItem() {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanRemoveItem(pItem); } +}; + +struct RlvPredCanNotRemoveItem +{ + RlvPredCanNotRemoveItem() {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotRemoveItem(pItem); } +}; + +struct RlvPredIsEqualOrLinkedItem +{ + RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {} + RlvPredIsEqualOrLinkedItem(const LLUUID& idItem); + bool operator()(const LLViewerInventoryItem* pItem) const; +protected: + const LLViewerInventoryItem* m_pItem; +}; + +template<typename T> struct RlvPredValuesEqual +{ + bool operator()(const T* pT2) const { return (pT1) && (pT2) && (*pT1 == *pT2); } + const T* pT1; +}; + +// ============================================================================ +// Inlined class member functions +// + +// Checked: 2010-10-31 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +inline const std::string& RlvStrings::getAnonym(const LLAvatarName& avName) +{ + return getAnonym(avName.getDisplayName()); +} + +// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.2a +inline bool RlvUtil::isEmote(const std::string& strUTF8Text) +{ + return (strUTF8Text.length() > 4) && ( (strUTF8Text.compare(0, 4, "/me ") == 0) || (strUTF8Text.compare(0, 4, "/me'") == 0) ); +} + +// Checked: 2010-03-09 (RLVa-1.2.0b) | Added: RLVa-1.0.2a +inline bool RlvUtil::isValidReplyChannel(S32 nChannel, bool fLoopback /*=false*/) +{ + return (nChannel > ((!fLoopback) ? 0 : -1)) && (CHAT_CHANNEL_DEBUG != nChannel); +} + +// Checked: 2009-08-05 (RLVa-1.0.1e) | Added: RLVa-1.0.0e +inline bool RlvUtil::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text) +{ + S32 nChannel; + return (LLStringUtil::convertToS32(strChannel, nChannel)) ? sendChatReply(nChannel, strUTF8Text) : false; +} + +// ============================================================================ + +#endif // RLV_COMMON_H diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h new file mode 100644 index 0000000000000000000000000000000000000000..8026b59b57ccd590bd958b22525cba5ef20027d6 --- /dev/null +++ b/indra/newview/rlvdefines.h @@ -0,0 +1,419 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_DEFINES_H +#define RLV_DEFINES_H + +// ============================================================================ +// Defines +// + +// Version of the specifcation we report +const S32 RLV_VERSION_MAJOR = 3; +const S32 RLV_VERSION_MINOR = 2; +const S32 RLV_VERSION_PATCH = 1; +const S32 RLV_VERSION_BUILD = 0; + +// Version of the specifcation we report (in compatibility mode) +const S32 RLV_VERSION_MAJOR_COMPAT = 2; +const S32 RLV_VERSION_MINOR_COMPAT = 8; +const S32 RLV_VERSION_PATCH_COMPAT = 0; +const S32 RLV_VERSION_BUILD_COMPAT = 0; + +// Implementation version +const S32 RLVa_VERSION_MAJOR = 2; +const S32 RLVa_VERSION_MINOR = 2; +const S32 RLVa_VERSION_PATCH = 2; + +// Uncomment before a final release +//#define RLV_RELEASE + +// Defining these makes it easier if we ever need to change our tag +#define RLV_WARNS LL_WARNS("RLV") +#define RLV_INFOS LL_INFOS("RLV") +#define RLV_DEBUGS LL_DEBUGS("RLV") +#define RLV_ENDL LL_ENDL +#define RLV_VERIFY(f) if (!(f)) { RlvUtil::notifyFailedAssertion(#f, __FILE__, __LINE__); } + +#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + // Turn on extended debugging information + #define RLV_DEBUG + // Make sure we halt execution on errors + #define RLV_ERRS LL_ERRS("RLV") + // Keep our asserts separate from LL's + #define RLV_ASSERT(f) if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; } + #define RLV_ASSERT_DBG(f) RLV_ASSERT(f) +#else + // Don't halt execution on errors in release + #define RLV_ERRS LL_WARNS("RLV") + // We don't want to check assertions in release builds + #ifndef RLV_RELEASE + #define RLV_ASSERT(f) RLV_VERIFY(f) + #define RLV_ASSERT_DBG(f) + #else + #define RLV_ASSERT(f) + #define RLV_ASSERT_DBG(f) + #endif // RLV_RELEASE +#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG + +#define RLV_ROOT_FOLDER "#RLV" +#define RLV_CMD_PREFIX '@' +#define RLV_MODIFIER_ANIMATION_FREQUENCY 10 +#define RLV_MODIFIER_TPLOCAL_DEFAULT 256.f // Any teleport that's more than a region away is non-local +#define RLV_MODIFIER_FARTOUCH_DEFAULT 1.5f // Specifies the default @fartouch distance +#define RLV_MODIFIER_SITTP_DEFAULT 1.5f // Specifies the default @sittp distance +#define RLV_OPTION_SEPARATOR ";" // Default separator used in command options +#define RLV_PUTINV_PREFIX "#RLV/~" +#define RLV_PUTINV_SEPARATOR "/" +#define RLV_PUTINV_MAXDEPTH 4 +#define RLV_SETGROUP_THROTTLE 60.f +#define RLV_SETROT_OFFSET F_PI_BY_TWO // @setrot is off by 90 degrees with the rest of SL +#define RLV_STRINGS_FILE "rlva_strings.xml" + +#define RLV_FOLDER_FLAG_NOSTRIP "nostrip" +#define RLV_FOLDER_PREFIX_HIDDEN '.' +#define RLV_FOLDER_PREFIX_PUTINV '~' +#define RLV_FOLDER_INVALID_CHARS "/" + +// ============================================================================ +// Enumeration declarations +// + +// NOTE: any changes to this enumeration should be reflected in the RlvBehaviourDictionary constructor +enum ERlvBehaviour { + RLV_BHVR_DETACH = 0, // "detach" + RLV_BHVR_ADDATTACH, // "addattach" + RLV_BHVR_REMATTACH, // "remattach" + RLV_BHVR_ADDOUTFIT, // "addoutfit" + RLV_BHVR_REMOUTFIT, // "remoutfit" + RLV_BHVR_SHAREDWEAR, // "sharedwear" + RLV_BHVR_SHAREDUNWEAR, // "sharedunwear" + RLV_BHVR_UNSHAREDWEAR, // "unsharedwear" + RLV_BHVR_UNSHAREDUNWEAR, // "unsharedunwear" + RLV_BHVR_EMOTE, // "emote" + RLV_BHVR_SENDCHAT, // "sendchat" + RLV_BHVR_RECVCHAT, // "recvchat" + RLV_BHVR_RECVCHATFROM, // "recvchatfrom" + RLV_BHVR_RECVEMOTE, // "recvemote" + RLV_BHVR_RECVEMOTEFROM, // "recvemotefrom" + RLV_BHVR_REDIRCHAT, // "redirchat" + RLV_BHVR_REDIREMOTE, // "rediremote" + RLV_BHVR_CHATWHISPER, // "chatwhisper" + RLV_BHVR_CHATNORMAL, // "chatnormal" + RLV_BHVR_CHATSHOUT, // "chatshout" + RLV_BHVR_SENDCHANNEL, + RLV_BHVR_SENDCHANNELEXCEPT, + RLV_BHVR_SENDIM, // "sendim" + RLV_BHVR_SENDIMTO, // "sendimto" + RLV_BHVR_RECVIM, // "recvim" + RLV_BHVR_RECVIMFROM, // "recvimfrom" + RLV_BHVR_STARTIM, // "startim" + RLV_BHVR_STARTIMTO, // "startimto" + RLV_BHVR_SENDGESTURE, + RLV_BHVR_PERMISSIVE, // "permissive" + RLV_BHVR_NOTIFY, // "notify" + RLV_BHVR_SHOWINV, // "showinv" + RLV_BHVR_SHOWMINIMAP, // "showminimap" + RLV_BHVR_SHOWWORLDMAP, // "showworldmap" + RLV_BHVR_SHOWLOC, // "showloc" + RLV_BHVR_SHOWNAMES, // "shownames" + RLV_BHVR_SHOWNAMETAGS, // "shownametags" + RLV_BHVR_SHOWNEARBY, + RLV_BHVR_SHOWHOVERTEXT, // "showhovertext" + RLV_BHVR_SHOWHOVERTEXTHUD, // "showhovertexthud" + RLV_BHVR_SHOWHOVERTEXTWORLD, // "showhovertextworld" + RLV_BHVR_SHOWHOVERTEXTALL, // "showhovertextall" + RLV_BHVR_SHOWSELF, + RLV_BHVR_SHOWSELFHEAD, + RLV_BHVR_TPLM, // "tplm" + RLV_BHVR_TPLOC, // "tploc" + RLV_BHVR_TPLOCAL, + RLV_BHVR_TPLURE, // "tplure" + RLV_BHVR_TPREQUEST, // "tprequest" + RLV_BHVR_VIEWNOTE, // "viewnote" + RLV_BHVR_VIEWSCRIPT, // "viewscript" + RLV_BHVR_VIEWTEXTURE, // "viewtexture" + RLV_BHVR_ACCEPTPERMISSION, // "acceptpermission" + RLV_BHVR_ACCEPTTP, // "accepttp" + RLV_BHVR_ACCEPTTPREQUEST, // "accepttprequest" + RLV_BHVR_ALLOWIDLE, // "allowidle" + RLV_BHVR_EDIT, // "edit" + RLV_BHVR_EDITOBJ, // "editobj" + RLV_BHVR_REZ, // "rez" + RLV_BHVR_FARTOUCH, // "fartouch" + RLV_BHVR_INTERACT, // "interact" + RLV_BHVR_TOUCHTHIS, // "touchthis" + RLV_BHVR_TOUCHATTACH, // "touchattach" + RLV_BHVR_TOUCHATTACHSELF, // "touchattachself" + RLV_BHVR_TOUCHATTACHOTHER, // "touchattachother" + RLV_BHVR_TOUCHHUD, // "touchhud" + RLV_BHVR_TOUCHWORLD, // "touchworld" + RLV_BHVR_TOUCHALL, // "touchall" + RLV_BHVR_TOUCHME, // "touchme" + RLV_BHVR_FLY, // "fly" + RLV_BHVR_JUMP, // "jump" + RLV_BHVR_SETGROUP, // "setgroup" + RLV_BHVR_UNSIT, // "unsit" + RLV_BHVR_SIT, // "sit" + RLV_BHVR_SITTP, // "sittp" + RLV_BHVR_STANDTP, // "standtp" + RLV_BHVR_SETDEBUG, // "setdebug" + RLV_BHVR_SETENV, // "setenv" + RLV_BHVR_ALWAYSRUN, // "alwaysrun" + RLV_BHVR_TEMPRUN, // "temprun" + RLV_BHVR_DETACHME, // "detachme" + RLV_BHVR_ATTACHTHIS, // "attachthis" + RLV_BHVR_ATTACHTHISEXCEPT, // "attachthis_except" + RLV_BHVR_DETACHTHIS, // "detachthis" + RLV_BHVR_DETACHTHISEXCEPT, // "detachthis_except" + RLV_BHVR_ADJUSTHEIGHT, // "adjustheight" + RLV_BHVR_GETHEIGHTOFFSET, // "getheightoffset" + RLV_BHVR_TPTO, // "tpto" + RLV_BHVR_VERSION, // "version" + RLV_BHVR_VERSIONNEW, // "versionnew" + RLV_BHVR_VERSIONNUM, // "versionnum" + RLV_BHVR_GETATTACH, // "getattach" + RLV_BHVR_GETATTACHNAMES, // "getattachnames" + RLV_BHVR_GETADDATTACHNAMES, // "getaddattachnames" + RLV_BHVR_GETREMATTACHNAMES, // "getremattachnames" + RLV_BHVR_GETOUTFIT, // "getoutfit" + RLV_BHVR_GETOUTFITNAMES, // "getoutfitnames" + RLV_BHVR_GETADDOUTFITNAMES, // "getaddoutfitnames" + RLV_BHVR_GETREMOUTFITNAMES, // "getremoutfitnames" + RLV_BHVR_FINDFOLDER, // "findfolder" + RLV_BHVR_FINDFOLDERS, // "findfolders" + RLV_BHVR_GETPATH, // "getpath" + RLV_BHVR_GETPATHNEW, // "getpathnew" + RLV_BHVR_GETINV, // "getinv" + RLV_BHVR_GETINVWORN, // "getinvworn" + RLV_BHVR_GETGROUP, // "getgroup" + RLV_BHVR_GETSITID, // "getsitid" + RLV_BHVR_GETCOMMAND, // "getcommand" + RLV_BHVR_GETSTATUS, // "getstatus" + RLV_BHVR_GETSTATUSALL, // "getstatusall" + RLV_CMD_FORCEWEAR, // Internal representation of all force wear commands + + // Camera (behaviours) + RLV_BHVR_SETCAM, // Gives an object exclusive control of the user's camera + RLV_BHVR_SETCAM_AVDIST, // Distance at which nearby avatars turn into a silhouette + RLV_BHVR_SETCAM_AVDISTMIN, // Enforces a minimum distance from the avatar (in m) + RLV_BHVR_SETCAM_AVDISTMAX, // Enforces a maximum distance from the avatar (in m) + RLV_BHVR_SETCAM_ORIGINDISTMIN, // Enforces a minimum distance from the camera origin (in m) + RLV_BHVR_SETCAM_ORIGINDISTMAX, // Enforces a maximum distance from the camera origin (in m) + RLV_BHVR_SETCAM_EYEOFFSET, // Changes the default camera offset + RLV_BHVR_SETCAM_FOCUSOFFSET, // Changes the default camera focus offset + RLV_BHVR_SETCAM_FOCUS, // Forces the camera focus and/or position to a specific object, avatar or position + RLV_BHVR_SETCAM_FOV, // Changes the current - vertical - field of view + RLV_BHVR_SETCAM_FOVMIN, // Enforces a minimum - vertical - FOV (in degrees) + RLV_BHVR_SETCAM_FOVMAX, // Enforces a maximum - vertical - FOV (in degrees) + RLV_BHVR_SETCAM_MOUSELOOK, // Prevent the user from going into mouselook + RLV_BHVR_SETCAM_TEXTURES, // Replaces all textures with the specified texture (or the default unrezzed one) + RLV_BHVR_SETCAM_UNLOCK, // Forces the camera focus to the user's avatar + // Camera (behaviours - deprecated) + RLV_BHVR_CAMZOOMMIN, // Enforces a minimum - vertical - FOV angle of 60° / multiplier + RLV_BHVR_CAMZOOMMAX, // Enforces a maximum - vertical - FOV angle of 60° / multiplier + // Camera (reply) + RLV_BHVR_GETCAM_AVDIST, // Returns the current minimum distance between the camera and the user's avatar + RLV_BHVR_GETCAM_AVDISTMIN, // Returns the active (if any) minimum distance between the camera and the user's avatar + RLV_BHVR_GETCAM_AVDISTMAX, // Returns the active (if any) maxmimum distance between the camera and the user's avatar + RLV_BHVR_GETCAM_FOV, // Returns the current field of view angle (in radians) + RLV_BHVR_GETCAM_FOVMIN, // Returns the active (if any) minimum field of view angle (in radians) + RLV_BHVR_GETCAM_FOVMAX, // Enforces a maximum (if any) maximum field of view angle (in radians) + RLV_BHVR_GETCAM_TEXTURES, // Returns the active (if any) replace texture UUID + // Camera (force) + RLV_BHVR_SETCAM_MODE, // Switch the user's camera into the specified mode (e.g. mouselook or thirdview) + + // Overlay + RLV_BHVR_SETOVERLAY, // Gives an object exclusive control of the overlay + RLV_BHVR_SETOVERLAY_ALPHA, // Changes the overlay texture's transparency level + RLV_BHVR_SETOVERLAY_TEXTURE, // Changes the overlay texture + RLV_BHVR_SETOVERLAY_TINT, // Changes the tint that's applied to the overlay texture + RLV_BHVR_SETOVERLAY_TOUCH, // Block world interaction (=touching) based on the alpha channel of the overlay texture + RLV_BHVR_SETOVERLAY_TWEEN, // Animate between the current overlay settings and the supplied values + + RLV_BHVR_COUNT, + RLV_BHVR_UNKNOWN +}; + +enum ERlvBehaviourModifier +{ + RLV_MODIFIER_FARTOUCHDIST, // Radius of a sphere around the user in which they can interact with the world + RLV_MODIFIER_OVERLAY_ALPHA, // Transparency level of the overlay texture (in addition to the texture's own alpha channel) + RLV_MODIFIER_OVERLAY_TEXTURE, // Specifies the UUID of the overlay texture + RLV_MODIFIER_OVERLAY_TINT, // The tint that's applied to the overlay texture + RLV_MODIFIER_OVERLAY_TOUCH, // Determines whether the overlay texture's alpha channel will be used to allow/block world interaction + RLV_MODIFIER_RECVIMDISTMIN, // Minimum distance to receive an IM from an otherwise restricted sender (squared value) + RLV_MODIFIER_RECVIMDISTMAX, // Maximum distance to receive an IM from an otherwise restricted sender (squared value) + RLV_MODIFIER_SENDIMDISTMIN, // Minimum distance to send an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_SENDIMDISTMAX, // Maximum distance to send an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_STARTIMDISTMIN, // Minimum distance to start an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_STARTIMDISTMAX, // Maximum distance to start an IM to an otherwise restricted recipient (squared value) + RLV_MODIFIER_SETCAM_AVDIST, // Distance at which nearby avatars turn into a silhouette (normal value) + RLV_MODIFIER_SETCAM_AVDISTMIN, // Minimum distance between the camera position and the user's avatar (normal value) + RLV_MODIFIER_SETCAM_AVDISTMAX, // Maximum distance between the camera position and the user's avatar (normal value) + RLV_MODIFIER_SETCAM_ORIGINDISTMIN, // Minimum distance between the camera position and the origin point (normal value) + RLV_MODIFIER_SETCAM_ORIGINDISTMAX, // Maximum distance between the camera position and the origin point (normal value) + RLV_MODIFIER_SETCAM_EYEOFFSET, // Specifies the default camera's offset from the camera (vector) + RLV_MODIFIER_SETCAM_FOCUSOFFSET, // Specifies the default camera's focus (vector) + RLV_MODIFIER_SETCAM_FOVMIN, // Minimum value for the camera's field of view (angle in radians) + RLV_MODIFIER_SETCAM_FOVMAX, // Maximum value for the camera's field of view (angle in radians) + RLV_MODIFIER_SETCAM_TEXTURE, // Specifies the UUID of the texture used to texture the world view + RLV_MODIFIER_SITTPDIST, + RLV_MODIFIER_TPLOCALDIST, + + RLV_MODIFIER_COUNT, + RLV_MODIFIER_UNKNOWN +}; + +enum ERlvBehaviourOptionType +{ + RLV_OPTION_NONE, // Behaviour takes no parameters + RLV_OPTION_EXCEPTION, // Behaviour requires an exception as a parameter + RLV_OPTION_NONE_OR_EXCEPTION, // Behaviour takes either no parameters or an exception + RLV_OPTION_MODIFIER, // Behaviour requires a modifier as a parameter + RLV_OPTION_NONE_OR_MODIFIER // Behaviour takes either no parameters or a modifier +}; + +enum ERlvParamType { + RLV_TYPE_UNKNOWN = 0x00, + RLV_TYPE_ADD = 0x01, // <param> == "n"|"add" + RLV_TYPE_REMOVE = 0x02, // <param> == "y"|"rem" + RLV_TYPE_FORCE = 0x04, // <param> == "force" + RLV_TYPE_REPLY = 0x08, // <param> == <number> + RLV_TYPE_CLEAR = 0x10, + RLV_TYPE_ADDREM = RLV_TYPE_ADD | RLV_TYPE_REMOVE +}; + +enum ERlvCmdRet { + RLV_RET_UNKNOWN = 0x0000, // Unknown error (should only be used internally) + RLV_RET_RETAINED, // Command was retained + RLV_RET_SUCCESS = 0x0100, // Command executed succesfully + RLV_RET_SUCCESS_UNSET, // Command executed succesfully (RLV_TYPE_REMOVE for an unrestricted behaviour) + RLV_RET_SUCCESS_DUPLICATE, // Command executed succesfully (RLV_TYPE_ADD for an already restricted behaviour) + RLV_RET_SUCCESS_DEPRECATED, // Command executed succesfully but has been marked as deprecated + RLV_RET_SUCCESS_DELAYED, // Command parsed valid but will execute at a later time + RLV_RET_FAILED = 0x0200, // Command failed (general failure) + RLV_RET_FAILED_SYNTAX, // Command failed (syntax error) + RLV_RET_FAILED_OPTION, // Command failed (invalid option) + RLV_RET_FAILED_PARAM, // Command failed (invalid param) + RLV_RET_FAILED_LOCK, // Command failed (command is locked by another object) + RLV_RET_FAILED_DISABLED, // Command failed (command disabled by user) + RLV_RET_FAILED_UNKNOWN, // Command failed (unknown command) + RLV_RET_FAILED_NOSHAREDROOT, // Command failed (missing #RLV) + RLV_RET_FAILED_DEPRECATED, // Command failed (deprecated and no longer supported) + RLV_RET_FAILED_NOBEHAVIOUR, // Command failed (force modifier on an object with no active restrictions) + RLV_RET_FAILED_BLOCKED, // Command failed (object is blocked) + RLV_RET_FAILED_THROTTLED, // Command failed (throttled) + RLV_RET_NO_PROCESSOR // Command doesn't have a template processor define (legacy code) +}; +#define RLV_RET_SUCCEEDED(eCmdRet) (((eCmdRet) & RLV_RET_SUCCESS) == RLV_RET_SUCCESS) + +enum ERlvExceptionCheck +{ + RLV_CHECK_PERMISSIVE, // Exception can be set by any object + RLV_CHECK_STRICT, // Exception must be set by all objects holding the restriction + RLV_CHECK_DEFAULT // Permissive or strict will be determined by currently enforced restrictions +}; + +enum ERlvLockMask +{ + RLV_LOCK_NONE = 0x00, + RLV_LOCK_ADD = 0x01, + RLV_LOCK_REMOVE = 0x02, + RLV_LOCK_ANY = RLV_LOCK_ADD | RLV_LOCK_REMOVE +}; + +enum ERlvWearMask +{ + RLV_WEAR_LOCKED = 0x00, // User can not wear the item at all + RLV_WEAR_ADD = 0x01, // User can wear the item in addition to what's already worn + RLV_WEAR_REPLACE = 0x02, // User can wear the item and replace what's currently worn + RLV_WEAR = 0x03 // Convenience: combines RLV_WEAR_ADD and RLV_WEAR_REPLACE +}; + +enum ERlvAttachGroupType +{ + RLV_ATTACHGROUP_HEAD = 0, + RLV_ATTACHGROUP_TORSO, + RLV_ATTACHGROUP_ARMS, + RLV_ATTACHGROUP_LEGS, + RLV_ATTACHGROUP_HUD, + RLV_ATTACHGROUP_COUNT, + RLV_ATTACHGROUP_INVALID +}; + +// ============================================================================ +// Settings +// + +#define RLV_SETTING_MAIN "RestrainedLove" +#define RLV_SETTING_DEBUG "RestrainedLoveDebug" +#define RLV_SETTING_CANOOC "RestrainedLoveCanOOC" +#define RLV_SETTING_FORBIDGIVETORLV "RestrainedLoveForbidGiveToRLV" +#define RLV_SETTING_NOSETENV "RestrainedLoveNoSetEnv" +#define RLV_SETTING_SHOWELLIPSIS "RestrainedLoveShowEllipsis" +#define RLV_SETTING_WEARADDPREFIX "RestrainedLoveStackWhenFolderBeginsWith" +#define RLV_SETTING_WEARREPLACEPREFIX "RestrainedLoveReplaceWhenFolderBeginsWith" + +#define RLV_SETTING_DEBUGHIDEUNSETDUP "RLVaDebugHideUnsetDuplicate" +#define RLV_SETTING_ENABLECOMPOSITES "RLVaEnableCompositeFolders" +#define RLV_SETTING_ENABLELEGACYNAMING "RLVaEnableLegacyNaming" +#define RLV_SETTING_ENABLESHAREDWEAR "RLVaEnableSharedWear" +#define RLV_SETTING_ENABLETEMPATTACH "RLVaEnableTemporaryAttachments" +#define RLV_SETTING_HIDELOCKEDLAYER "RLVaHideLockedLayers" +#define RLV_SETTING_HIDELOCKEDATTACH "RLVaHideLockedAttachments" +#define RLV_SETTING_HIDELOCKEDINVENTORY "RLVaHideLockedInventory" +#define RLV_SETTING_LOGINLASTLOCATION "RLVaLoginLastLocation" +#define RLV_SETTING_SHAREDINVAUTORENAME "RLVaSharedInvAutoRename" +#define RLV_SETTING_SHOWASSERTIONFAIL "RLVaShowAssertionFailures" +#define RLV_SETTING_SPLITREDIRECTCHAT "RLVaSplitRedirectChat" +#define RLV_SETTING_TOPLEVELMENU "RLVaTopLevelMenu" +#define RLV_SETTING_WEARREPLACEUNLOCKED "RLVaWearReplaceUnlocked" + +#define RLV_SETTING_FIRSTUSE_PREFIX "FirstRLV" +#define RLV_SETTING_FIRSTUSE_GIVETORLV RLV_SETTING_FIRSTUSE_PREFIX"GiveToRLV" + +// ============================================================================ +// Strings (see rlva_strings.xml) +// + +#define RLV_STRING_HIDDEN "hidden_generic" +#define RLV_STRING_HIDDEN_PARCEL "hidden_parcel" +#define RLV_STRING_HIDDEN_REGION "hidden_region" + +#define RLV_STRING_BLOCKED_AUTOPILOT "blocked_autopilot" +#define RLV_STRING_BLOCKED_GENERIC "blocked_generic" +#define RLV_STRING_BLOCKED_GROUPCHANGE "blocked_groupchange" +#define RLV_STRING_BLOCKED_INVFOLDER "blocked_invfolder" +#define RLV_STRING_BLOCKED_PERMATTACH "blocked_permattach" +#define RLV_STRING_BLOCKED_PERMTELEPORT "blocked_permteleport" +#define RLV_STRING_BLOCKED_RECVIM "blocked_recvim" +#define RLV_STRING_BLOCKED_RECVIM_REMOTE "blocked_recvim_remote" +#define RLV_STRING_BLOCKED_SENDIM "blocked_sendim" +#define RLV_STRING_BLOCKED_STARTCONF "blocked_startconf" +#define RLV_STRING_BLOCKED_STARTIM "blocked_startim" +#define RLV_STRING_BLOCKED_TELEPORT "blocked_teleport" +#define RLV_STRING_BLOCKED_TELEPORT_OFFER "blocked_teleport_offer" +#define RLV_STRING_BLOCKED_TPLUREREQ_REMOTE "blocked_tplurerequest_remote" +#define RLV_STRING_BLOCKED_VIEWXXX "blocked_viewxxx" +#define RLV_STRING_BLOCKED_WIREFRAME "blocked_wireframe" +#define RLV_STRING_STOPIM_NOSESSION "stopim_nosession" +#define RLV_STRING_STOPIM_ENDSESSION_REMOTE "stopim_endsession_remote" +#define RLV_STRING_STOPIM_ENDSESSION_LOCAL "stopim_endsession_local" + +// ============================================================================ + +#endif // RLV_DEFINES_H diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..baa2be38fcfb704af74fe19fa5c5e0094c573feb --- /dev/null +++ b/indra/newview/rlvextensions.cpp @@ -0,0 +1,638 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "lldaycyclemanager.h" +#include "llvoavatarself.h" +#include "llwlparammanager.h" + +#include "rlvextensions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" + +// ============================================================================ + +class RlvWindLightControl +{ +public: + enum EType { TYPE_COLOR, TYPE_COLOR_R, TYPE_FLOAT, TYPE_UNKNOWN }; + enum EColorComponent { COMPONENT_R, COMPONENT_G, COMPONENT_B, COMPONENT_I, COMPONENT_NONE }; +public: + RlvWindLightControl(WLColorControl* pCtrl, bool fColorR) : m_eType((!fColorR) ? TYPE_COLOR: TYPE_COLOR_R), m_pColourCtrl(pCtrl), m_pFloatCtrl(NULL) {} + RlvWindLightControl(WLFloatControl* pCtrl) : m_eType(TYPE_FLOAT), m_pColourCtrl(NULL), m_pFloatCtrl(pCtrl) {} + + EType getControlType() const { return m_eType; } + bool isColorType() const { return (TYPE_COLOR == m_eType) || (TYPE_COLOR_R == m_eType); } + bool isFloatType() const { return (TYPE_FLOAT == m_eType); } + // TYPE_COLOR and TYPE_COLOR_R + F32 getColorComponent(EColorComponent eComponent, bool& fError) const; + LLVector4 getColorVector(bool& fError) const; + bool setColorComponent(EColorComponent eComponent, F32 nValue); + // TYPE_FLOAT + F32 getFloat(bool& fError) const; + bool setFloat(F32 nValue); + + static EColorComponent getComponentFromCharacter(char ch); +protected: + EType m_eType; // Type of the WindLight control + WLColorControl* m_pColourCtrl; + WLFloatControl* m_pFloatCtrl; +}; + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +static F32 get_intensity_from_color(const LLVector4& v) +{ + return llmax(v.mV[0], v.mV[1], v.mV[2]); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +F32 RlvWindLightControl::getColorComponent(EColorComponent eComponent, bool& fError) const +{ + switch (eComponent) + { + case COMPONENT_R: return getColorVector(fError).mV[0]; + case COMPONENT_G: return getColorVector(fError).mV[1]; + case COMPONENT_B: return getColorVector(fError).mV[2]; + case COMPONENT_I: return get_intensity_from_color(getColorVector(fError)); // SL-2.8: Always seems to be 1.0 so get it manually + default : RLV_ASSERT(false); fError = true; return 0.0; + } +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +RlvWindLightControl::EColorComponent RlvWindLightControl::getComponentFromCharacter(char ch) +{ + if (('r' == ch) || ('x' == ch)) + return COMPONENT_R; + else if (('g' == ch) || ('y' == ch)) + return COMPONENT_G; + else if (('b' == ch) || ('d' == ch)) + return COMPONENT_B; + else if ('i' == ch) + return COMPONENT_I; + return COMPONENT_NONE; +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +LLVector4 RlvWindLightControl::getColorVector(bool& fError) const +{ + if ((fError = !isColorType())) + return LLVector4(0, 0, 0, 0); + F32 nMult = (m_pColourCtrl->isSunOrAmbientColor) ? 3.0f : ((m_pColourCtrl->isBlueHorizonOrDensity) ? 2.0f : 1.0f); + return LLWLParamManager::getInstance()->mCurParams.getVector(m_pColourCtrl->mName, fError) / nMult; +} + +// Checked: 2011-08-28 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +bool RlvWindLightControl::setColorComponent(EColorComponent eComponent, F32 nValue) +{ + if (isColorType()) + { + nValue *= (m_pColourCtrl->isSunOrAmbientColor) ? 3.0f : ((m_pColourCtrl->isBlueHorizonOrDensity) ? 2.0f : 1.0f); + if (COMPONENT_I == eComponent) // (See: LLFloaterWindLight::onColorControlIMoved) + { + if (m_pColourCtrl->hasSliderName) + { + F32 curMax = llmax(m_pColourCtrl->r, m_pColourCtrl->g, m_pColourCtrl->b); + if ( (0.0f == nValue) || (0.0f == curMax) ) + { + m_pColourCtrl->r = m_pColourCtrl->g = m_pColourCtrl->b = m_pColourCtrl->i = nValue; + } + else + { + F32 nDelta = (nValue - curMax) / curMax; + m_pColourCtrl->r *= (1.0f + nDelta); + m_pColourCtrl->g *= (1.0f + nDelta); + m_pColourCtrl->b *= (1.0f + nDelta); + m_pColourCtrl->i = nValue; + } + } + } + else // (See: LLFloaterWindLight::onColorControlRMoved) + { + F32* pnValue = (COMPONENT_R == eComponent) ? &m_pColourCtrl->r : (COMPONENT_G == eComponent) ? &m_pColourCtrl->g : (COMPONENT_B == eComponent) ? &m_pColourCtrl->b : NULL; + if (pnValue) + *pnValue = nValue; + if (m_pColourCtrl->hasSliderName) + m_pColourCtrl->i = llmax(m_pColourCtrl->r, m_pColourCtrl->g, m_pColourCtrl->b); + } + m_pColourCtrl->update(LLWLParamManager::getInstance()->mCurParams); + LLWLParamManager::getInstance()->propagateParameters(); + } + return isColorType(); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +F32 RlvWindLightControl::getFloat(bool& fError) const +{ + return (!(fError = (TYPE_FLOAT != m_eType))) ? LLWLParamManager::getInstance()->mCurParams.getVector(m_pFloatCtrl->mName, fError).mV[0] * m_pFloatCtrl->mult : 0.0; +} + +// Checked: 2011-08-28 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +bool RlvWindLightControl::setFloat(F32 nValue) +{ + if (TYPE_FLOAT == m_eType) + { + m_pFloatCtrl->x = nValue / m_pFloatCtrl->mult; + m_pFloatCtrl->update(LLWLParamManager::getInstance()->mCurParams); + LLWLParamManager::getInstance()->propagateParameters(); + } + return (TYPE_FLOAT == m_eType); +} + +// ============================================================================ + +class RlvWindLight : public LLSingleton<RlvWindLight> +{ + LLSINGLETON(RlvWindLight); +public: + std::string getValue(const std::string& strSetting, bool& fError); + bool setValue(const std::string& strRlvName, const std::string& strValue); + +protected: + std::map<std::string, RlvWindLightControl> m_ControlLookupMap; +}; + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +RlvWindLight::RlvWindLight() +{ + LLWLParamManager* pWLParamMgr = LLWLParamManager::getInstance(); + + // TYPE_FLOAT + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudcoverage", RlvWindLightControl(&pWLParamMgr->mCloudCoverage))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudscale", RlvWindLightControl(&pWLParamMgr->mCloudScale))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("densitymultiplier", RlvWindLightControl(&pWLParamMgr->mDensityMult))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("distancemultiplier", RlvWindLightControl(&pWLParamMgr->mDistanceMult))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("maxaltitude", RlvWindLightControl(&pWLParamMgr->mMaxAlt))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("scenegamma", RlvWindLightControl(&pWLParamMgr->mWLGamma))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("hazedensity", RlvWindLightControl(&pWLParamMgr->mHazeDensity))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("hazehorizon", RlvWindLightControl(&pWLParamMgr->mHazeHorizon))); + // TYPE_COLOR + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("ambient", RlvWindLightControl(&pWLParamMgr->mAmbient, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("bluedensity", RlvWindLightControl(&pWLParamMgr->mBlueDensity, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("bluehorizon", RlvWindLightControl(&pWLParamMgr->mBlueHorizon, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloud", RlvWindLightControl(&pWLParamMgr->mCloudMain, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("cloudcolor", RlvWindLightControl(&pWLParamMgr->mCloudColor, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("clouddetail", RlvWindLightControl(&pWLParamMgr->mCloudDetail, false))); + m_ControlLookupMap.insert(std::pair<std::string, RlvWindLightControl>("sunmooncolor", RlvWindLightControl(&pWLParamMgr->mSunlight, false))); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +std::string RlvWindLight::getValue(const std::string& strSetting, bool& fError) +{ + LLWLParamManager* pWLParams = LLWLParamManager::getInstance(); + LLEnvManagerNew* pEnvMgr = LLEnvManagerNew::getInstance(); + + fError = false; // Assume we won't fail + if ("preset" == strSetting) + return (pEnvMgr->getUseFixedSky()) ? pEnvMgr->getSkyPresetName() : std::string(); + else if ("daycycle" == strSetting) + return (pEnvMgr->getUseDayCycle()) ? pEnvMgr->getDayCycleName() : std::string(); + + F32 nValue = 0.0f; + if ("daytime" == strSetting) + { + nValue = (pEnvMgr->getUseFixedSky()) ? pWLParams->mCurParams.getFloat("sun_angle", fError) / F_TWO_PI : -1.0f; + } + else if (("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting)) + { + pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fError); + RLV_ASSERT_DBG(!fError); + + if ("sunglowfocus" == strSetting) + nValue = -pWLParams->mGlow.b / 5.0f; + else + nValue = 2 - pWLParams->mGlow.r / 20.0f; + } + else if ("starbrightness" == strSetting) nValue = pWLParams->mCurParams.getStarBrightness(); + else if ("eastangle" == strSetting) nValue = pWLParams->mCurParams.getEastAngle() / F_TWO_PI; + else if ("sunmoonposition" == strSetting) nValue = pWLParams->mCurParams.getSunAngle() / F_TWO_PI; + else if ("cloudscrollx" == strSetting) nValue = pWLParams->mCurParams.getCloudScrollX() - 10.0f; + else if ("cloudscrolly" == strSetting) nValue = pWLParams->mCurParams.getCloudScrollY() - 10.0f; + else + { + std::map<std::string, RlvWindLightControl>::const_iterator itControl = m_ControlLookupMap.find(strSetting); + if (m_ControlLookupMap.end() != itControl) + { + switch (itControl->second.getControlType()) + { + case RlvWindLightControl::TYPE_FLOAT: + nValue = itControl->second.getFloat(fError); + break; + case RlvWindLightControl::TYPE_COLOR_R: + nValue = itControl->second.getColorComponent(RlvWindLightControl::COMPONENT_R, fError); + break; + default: + fError = true; + break; + } + } + else + { + // Couldn't find the exact name, check for a color control name + RlvWindLightControl::EColorComponent eComponent = RlvWindLightControl::getComponentFromCharacter(strSetting[strSetting.length() - 1]); + if (RlvWindLightControl::COMPONENT_NONE != eComponent) + itControl = m_ControlLookupMap.find(strSetting.substr(0, strSetting.length() - 1)); + if ( (m_ControlLookupMap.end() != itControl) && (itControl->second.isColorType()) ) + nValue = itControl->second.getColorComponent(eComponent, fError); + else + fError = true; + } + } + return llformat("%f", nValue); +} + +// Checked: 2011-08-29 (RLVa-1.4.1a) | Added: RLVa-1.4.1a +bool RlvWindLight::setValue(const std::string& strRlvName, const std::string& strValue) +{ + F32 nValue = 0.0f; + // Sanity check - make sure strValue specifies a number for all settings except "preset" and "daycycle" + if ( (RlvSettings::getNoSetEnv()) || + ( (!LLStringUtil::convertToF32(strValue, nValue)) && (("preset" != strRlvName) && ("daycycle" != strRlvName)) ) ) + { + return false; + } + + LLWLParamManager* pWLParams = LLWLParamManager::getInstance(); + LLEnvManagerNew* pEnvMgr = LLEnvManagerNew::getInstance(); + + if ("daytime" == strRlvName) + { + if (0.0f <= nValue) + { + pWLParams->mAnimator.deactivate(); + pWLParams->mAnimator.setDayTime(nValue); + pWLParams->mAnimator.update(pWLParams->mCurParams); + } + else + { + pEnvMgr->setUserPrefs(pEnvMgr->getWaterPresetName(), pEnvMgr->getSkyPresetName(), pEnvMgr->getDayCycleName(), false, true); + } + return true; + } + else if ("preset" == strRlvName) + { + std::string strPresetName = pWLParams->findPreset(strValue, LLEnvKey::SCOPE_LOCAL); + if (!strPresetName.empty()) + pEnvMgr->useSkyPreset(strPresetName); + return !strPresetName.empty(); + } + else if ("daycycle" == strRlvName) + { + std::string strPresetName = LLDayCycleManager::instance().findPreset(strValue); + if (!strPresetName.empty()) + pEnvMgr->useDayCycle(strValue, LLEnvKey::SCOPE_LOCAL); + return !strPresetName.empty(); + } + + bool fError = false; + pWLParams->mAnimator.deactivate(); + if (("sunglowfocus" == strRlvName) || ("sunglowsize" == strRlvName)) + { + pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fError); + RLV_ASSERT_DBG(!fError); + + if ("sunglowfocus" == strRlvName) + pWLParams->mGlow.b = -nValue * 5; + else + pWLParams->mGlow.r = (2 - nValue) * 20; + + pWLParams->mGlow.update(pWLParams->mCurParams); + pWLParams->propagateParameters(); + return true; + } + else if ("starbrightness" == strRlvName) + { + pWLParams->mCurParams.setStarBrightness(nValue); + return true; + } + else if (("eastangle" == strRlvName) || ("sunmoonposition" == strRlvName)) + { + if ("eastangle" == strRlvName) + pWLParams->mCurParams.setEastAngle(F_TWO_PI * nValue); + else + pWLParams->mCurParams.setSunAngle(F_TWO_PI * nValue); + + // Set the sun vector + pWLParams->mLightnorm.r = -sin(pWLParams->mCurParams.getEastAngle()) * cos(pWLParams->mCurParams.getSunAngle()); + pWLParams->mLightnorm.g = sin(pWLParams->mCurParams.getSunAngle()); + pWLParams->mLightnorm.b = cos(pWLParams->mCurParams.getEastAngle()) * cos(pWLParams->mCurParams.getSunAngle()); + pWLParams->mLightnorm.i = 1.f; + + pWLParams->propagateParameters(); + return true; + } + else if ("cloudscrollx" == strRlvName) + { + pWLParams->mCurParams.setCloudScrollX(nValue + 10.0f); + return true; + } + else if ("cloudscrolly" == strRlvName) + { + pWLParams->mCurParams.setCloudScrollY(nValue + 10.0f); + return true; + } + + std::map<std::string, RlvWindLightControl>::iterator itControl = m_ControlLookupMap.find(strRlvName); + if (m_ControlLookupMap.end() != itControl) + { + switch (itControl->second.getControlType()) + { + case RlvWindLightControl::TYPE_FLOAT: + return itControl->second.setFloat(nValue); + case RlvWindLightControl::TYPE_COLOR_R: + return itControl->second.setColorComponent(RlvWindLightControl::COMPONENT_R, nValue); + default: + RLV_ASSERT(false); + } + } + else + { + // Couldn't find the exact name, check for a color control name + RlvWindLightControl::EColorComponent eComponent = RlvWindLightControl::getComponentFromCharacter(strRlvName[strRlvName.length() - 1]); + if (RlvWindLightControl::COMPONENT_NONE != eComponent) + itControl = m_ControlLookupMap.find(strRlvName.substr(0, strRlvName.length() - 1)); + if ( (m_ControlLookupMap.end() != itControl) && (itControl->second.isColorType()) ) + return itControl->second.setColorComponent(eComponent, nValue); + } + return false; +} + +// ============================================================================ + +std::map<std::string, S16> RlvExtGetSet::m_DbgAllowed; +std::map<std::string, std::string> RlvExtGetSet::m_PseudoDebug; + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h +RlvExtGetSet::RlvExtGetSet() +{ + if (!m_DbgAllowed.size()) // m_DbgAllowed is static and should only be initialized once + { + m_DbgAllowed.insert(std::pair<std::string, S16>("AvatarSex", DBG_READ | DBG_WRITE | DBG_PSEUDO)); + m_DbgAllowed.insert(std::pair<std::string, S16>("RenderResolutionDivisor", DBG_READ | DBG_WRITE)); + m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_FORBIDGIVETORLV, DBG_READ)); + m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_NOSETENV, DBG_READ)); + m_DbgAllowed.insert(std::pair<std::string, S16>("WindLightUseAtmosShaders", DBG_READ)); + + // Cache persistance of every setting + LLControlVariable* pSetting; + for (std::map<std::string, S16>::iterator itDbg = m_DbgAllowed.begin(); itDbg != m_DbgAllowed.end(); ++itDbg) + { + if ( ((pSetting = gSavedSettings.getControl(itDbg->first)) != NULL) && (pSetting->isPersisted()) ) + itDbg->second |= DBG_PERSIST; + } + } +} + +// Checked: 2009-05-17 (RLVa-0.2.0a) +bool RlvExtGetSet::onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) +{ + return processCommand(rlvCmd, cmdRet); +} + +// Checked: 2009-05-17 (RLVa-0.2.0a) +bool RlvExtGetSet::onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) +{ + return processCommand(rlvCmd, cmdRet); +} + +// Checked: 2009-12-23 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k +bool RlvExtGetSet::processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet) +{ + std::string strBehaviour = rlvCmd.getBehaviour(), strGetSet, strSetting; + int idxSetting = strBehaviour.find('_'); + if ( (strBehaviour.length() >= 6) && (-1 != idxSetting) && ((int)strBehaviour.length() > idxSetting + 1) ) + { + strSetting = strBehaviour.substr(idxSetting + 1); + strBehaviour.erase(idxSetting); // Get rid of "_<setting>" + + strGetSet = strBehaviour.substr(0, 3); + strBehaviour.erase(0, 3); // Get rid of get/set + + if ("debug" == strBehaviour) + { + if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) ) + { + RlvUtil::sendChatReply(rlvCmd.getParam(), onGetDebug(strSetting)); + eRet = RLV_RET_SUCCESS; + return true; + } + else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) ) + { + if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETDEBUG, rlvCmd.getObjectID())) + eRet = onSetDebug(strSetting, rlvCmd.getOption()); + else + eRet = RLV_RET_FAILED_LOCK; + return true; + } + } + else if ("env" == strBehaviour) + { + bool fError = false; + if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) ) + { + RlvUtil::sendChatReply(rlvCmd.getParam(), RlvWindLight::instance().getValue(strSetting, fError)); + eRet = (!fError) ? RLV_RET_SUCCESS : RLV_RET_FAILED_UNKNOWN; + return true; + } + else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) ) + { + if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETENV, rlvCmd.getObjectID())) + eRet = (RlvWindLight::instance().setValue(strSetting, rlvCmd.getOption())) ? RLV_RET_SUCCESS : RLV_RET_FAILED_UNKNOWN; + else + eRet = RLV_RET_FAILED_LOCK; + return true; + } + } + } + else if ("setrot" == rlvCmd.getBehaviour()) + { + // NOTE: if <option> is invalid (or missing) altogether then RLV-1.17 will rotate to 0.0 (which is actually PI / 4) + F32 nAngle = 0.0f; + if (LLStringUtil::convertToF32(rlvCmd.getOption(), nAngle)) + { + nAngle = RLV_SETROT_OFFSET - nAngle; + + gAgentCamera.startCameraAnimation(); + + LLVector3 at(LLVector3::x_axis); + at.rotVec(nAngle, LLVector3::z_axis); + at.normalize(); + gAgent.resetAxes(at); + + eRet = RLV_RET_SUCCESS; + } + else + { + eRet = RLV_RET_FAILED_OPTION; + } + return true; + } + return false; +} + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h +bool RlvExtGetSet::findDebugSetting(std::string& strSetting, S16& flags) +{ + LLStringUtil::toLower(strSetting); // Convenience for non-RLV calls + + std::string strTemp; + for (std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.begin(); itSetting != m_DbgAllowed.end(); ++itSetting) + { + strTemp = itSetting->first; + LLStringUtil::toLower(strTemp); + + if (strSetting == strTemp) + { + strSetting = itSetting->first; + flags = itSetting->second; + return true; + } + } + return false; +} + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h +S16 RlvExtGetSet::getDebugSettingFlags(const std::string& strSetting) +{ + std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.find(strSetting); + return (itSetting != m_DbgAllowed.end()) ? itSetting->second : 0; +} + +// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h +std::string RlvExtGetSet::onGetDebug(std::string strSetting) +{ + S16 dbgFlags; + if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_READ) == DBG_READ) ) + { + if ((dbgFlags & DBG_PSEUDO) == 0) + { + LLControlVariable* pSetting = gSavedSettings.getControl(strSetting); + if (pSetting) + { + switch (pSetting->type()) + { + case TYPE_U32: + return llformat("%u", gSavedSettings.getU32(strSetting)); + case TYPE_S32: + return llformat("%d", gSavedSettings.getS32(strSetting)); + case TYPE_BOOLEAN: + return llformat("%d", gSavedSettings.getBOOL(strSetting)); + default: + RLV_ERRS << "Unexpected debug setting type" << LL_ENDL; + break; + } + } + } + else + { + return onGetPseudoDebug(strSetting); + } + } + return std::string(); +} + +// Checked: 2009-10-03 (RLVa-1.0.4e) | Added: RLVa-1.0.4e +std::string RlvExtGetSet::onGetPseudoDebug(const std::string& strSetting) +{ + // Skip sanity checking because it's all done in RlvExtGetSet::onGetDebug() already + if ("AvatarSex" == strSetting) + { + std::map<std::string, std::string>::const_iterator itPseudo = m_PseudoDebug.find(strSetting); + if (itPseudo != m_PseudoDebug.end()) + { + return itPseudo->second; + } + else + { + if (isAgentAvatarValid()) + return llformat("%d", (gAgentAvatarp->getSex() == SEX_MALE)); // [See LLFloaterCustomize::LLFloaterCustomize()] + } + } + return std::string(); +} + +// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e +ERlvCmdRet RlvExtGetSet::onSetDebug(std::string strSetting, const std::string& strValue) +{ + S16 dbgFlags; ERlvCmdRet eRet = RLV_RET_FAILED_UNKNOWN; + if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_WRITE) == DBG_WRITE) ) + { + eRet = RLV_RET_FAILED_OPTION; + if ((dbgFlags & DBG_PSEUDO) == 0) + { + LLControlVariable* pSetting = gSavedSettings.getControl(strSetting); + if (pSetting) + { + U32 u32Value; S32 s32Value; BOOL fValue; + switch (pSetting->type()) + { + case TYPE_U32: + if (LLStringUtil::convertToU32(strValue, u32Value)) + { + gSavedSettings.setU32(strSetting, u32Value); + eRet = RLV_RET_SUCCESS; + } + break; + case TYPE_S32: + if (LLStringUtil::convertToS32(strValue, s32Value)) + { + gSavedSettings.setS32(strSetting, s32Value); + eRet = RLV_RET_SUCCESS; + } + break; + case TYPE_BOOLEAN: + if (LLStringUtil::convertToBOOL(strValue, fValue)) + { + gSavedSettings.setBOOL(strSetting, fValue); + eRet = RLV_RET_SUCCESS; + } + break; + default: + RLV_ERRS << "Unexpected debug setting type" << LL_ENDL; + eRet = RLV_RET_FAILED; + break; + } + + // Default settings should persist if they were marked that way, but non-default settings should never persist + pSetting->setPersist( ((pSetting->isDefault()) && ((dbgFlags & DBG_PERSIST) == DBG_PERSIST)) ? LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO ); + } + } + else + { + eRet = onSetPseudoDebug(strSetting, strValue); + } + } + return eRet; +} + +// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e +ERlvCmdRet RlvExtGetSet::onSetPseudoDebug(const std::string& strSetting, const std::string& strValue) +{ + ERlvCmdRet eRet = RLV_RET_FAILED_OPTION; + if ("AvatarSex" == strSetting) + { + BOOL fValue; + if (LLStringUtil::convertToBOOL(strValue, fValue)) + { + m_PseudoDebug[strSetting] = strValue; + eRet = RLV_RET_SUCCESS; + } + } + return eRet; +} + +// ============================================================================ diff --git a/indra/newview/rlvextensions.h b/indra/newview/rlvextensions.h new file mode 100644 index 0000000000000000000000000000000000000000..08a6d1fca7b1022e53d1fbb3b9ab2ccd642eeeea --- /dev/null +++ b/indra/newview/rlvextensions.h @@ -0,0 +1,57 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_EXTENSIONS_H +#define RLV_EXTENSIONS_H + +#include "rlvcommon.h" + +// ============================================================================ +/* + * RlvExtGetSet + * ============ + * Implements @get_XXX:<option>=<channel> and @set_XXX:<option>=force + * + */ + +class RlvExtGetSet : public RlvExtCommandHandler +{ +public: + RlvExtGetSet(); + virtual ~RlvExtGetSet() {} + + virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); + virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet); +protected: + std::string onGetDebug(std::string strSetting); + std::string onGetPseudoDebug(const std::string& strSetting); + ERlvCmdRet onSetDebug(std::string strSetting, const std::string& strValue); + ERlvCmdRet onSetPseudoDebug(const std::string& strSetting, const std::string& strValue); + + bool processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet); + +public: + enum { DBG_READ = 0x01, DBG_WRITE = 0x02, DBG_PERSIST = 0x04, DBG_PSEUDO = 0x08 }; + static std::map<std::string, S16> m_DbgAllowed; + static std::map<std::string, std::string> m_PseudoDebug; + + static bool findDebugSetting(/*[in,out]*/ std::string& strSetting, /*[out]*/ S16& flags); + static S16 getDebugSettingFlags(const std::string& strSetting); +}; + +// ============================================================================ + +#endif // RLV_EXTENSIONS_H diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f90fa1259b841a828f1ab7a164b46ffba68ece9 --- /dev/null +++ b/indra/newview/rlvfloaters.cpp @@ -0,0 +1,834 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llappearancemgr.h" +#include "llavatarnamecache.h" +#include "llclipboard.h" +#include "llcombobox.h" +#include "llinventoryfunctions.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "llsdserialize.h" +#include "lltexteditor.h" +#include "llviewerjointattachment.h" +#include "llviewerobjectlist.h" +#include "llvoavatarself.h" + +#include "rlvfloaters.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvlocks.h" + +// ============================================================================ +// Helper functions +// + +// Checked: 2012-07-14 (RLVa-1.4.7) +std::string rlvGetItemName(const LLViewerInventoryItem* pItem) +{ + if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) ) + { + return llformat("%s (%s)", pItem->getName().c_str(), LLWearableType::getTypeName(pItem->getWearableType()).c_str()); + } + else if ( (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (isAgentAvatarValid()) ) + { + std::string strAttachPtName; + gAgentAvatarp->getAttachedPointName(pItem->getUUID(), strAttachPtName); + return llformat("%s (%s)", pItem->getName().c_str(), strAttachPtName.c_str()); + } + return (pItem) ? pItem->getName() : LLStringUtil::null; +} + +// Checked: 2012-07-14 (RLVa-1.4.7) +std::string rlvGetItemType(const LLViewerInventoryItem* pItem) +{ + if (pItem) + { + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return "Wearable"; + case LLAssetType::AT_OBJECT: + return "Attachment"; + default: + break; + } + } + return "Unknown"; +} + +std::string rlvGetItemNameFromObjID(const LLUUID& idObj, bool fIncludeAttachPt = true) +{ + const LLViewerObject* pObj = gObjectList.findObject(idObj); + if ( (pObj) && (pObj->isAvatar()) ) + { + LLAvatarName avName; + if (LLAvatarNameCache::get(pObj->getID(), &avName)) + return avName.getCompleteName(); + return ((LLVOAvatar*)pObj)->getFullname(); + } + + const LLViewerObject* pObjRoot = (pObj) ? pObj->getRootEdit() : NULL; + const LLViewerInventoryItem* pItem = ((pObjRoot) && (pObjRoot->isAttachment())) ? gInventory.getItem(pObjRoot->getAttachmentItemID()) : NULL; + + const std::string strItemName = (pItem) ? pItem->getName() : idObj.asString(); + if ( (!fIncludeAttachPt) || (!pObj) || (!pObj->isAttachment()) || (!isAgentAvatarValid()) ) + return strItemName; + + const LLViewerJointAttachment* pAttachPt = get_if_there(gAgentAvatarp->mAttachmentPoints, RlvAttachPtLookup::getAttachPointIndex(pObjRoot), (LLViewerJointAttachment*)NULL); + const std::string strAttachPtName = (pAttachPt) ? pAttachPt->getName() : std::string("Unknown"); + return llformat("%s (%s%s)", strItemName.c_str(), strAttachPtName.c_str(), (pObj == pObjRoot) ? "" : ", child"); +} + +// Checked: 2011-05-23 (RLVa-1.3.0c) | Added: RLVa-1.3.0c +bool rlvGetShowException(ERlvBehaviour eBhvr) +{ + switch (eBhvr) + { + case RLV_BHVR_RECVCHAT: + case RLV_BHVR_RECVEMOTE: + case RLV_BHVR_SENDIM: + case RLV_BHVR_RECVIM: + case RLV_BHVR_STARTIM: + case RLV_BHVR_TPLURE: + case RLV_BHVR_TPREQUEST: + case RLV_BHVR_ACCEPTTP: + case RLV_BHVR_ACCEPTTPREQUEST: + case RLV_BHVR_SHOWNAMES: + case RLV_BHVR_SHOWNAMETAGS: + return true; + default: + return false; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvLockMaskToString(ERlvLockMask eLockType) +{ + switch (eLockType) + { + case RLV_LOCK_ADD: + return "add"; + case RLV_LOCK_REMOVE: + return "rem"; + default: + return "unknown"; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvFolderLockPermissionToString(RlvFolderLocks::ELockPermission eLockPermission) +{ + switch (eLockPermission) + { + case RlvFolderLocks::PERM_ALLOW: + return "allow"; + case RlvFolderLocks::PERM_DENY: + return "deny"; + default: + return "unknown"; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvFolderLockScopeToString(RlvFolderLocks::ELockScope eLockScope) +{ + switch (eLockScope) + { + case RlvFolderLocks::SCOPE_NODE: + return "node"; + case RlvFolderLocks::SCOPE_SUBTREE: + return "subtree"; + default: + return "unknown"; + } +} + +// Checked: 2012-07-29 (RLVa-1.4.7) +std::string rlvFolderLockSourceToTarget(RlvFolderLocks::folderlock_source_t lockSource) +{ + switch (lockSource.first) + { + case RlvFolderLocks::ST_ATTACHMENT: + { + std::string strAttachName = rlvGetItemNameFromObjID(boost::get<LLUUID>(lockSource.second)); + return llformat("Attachment (%s)", strAttachName.c_str()); + } + case RlvFolderLocks::ST_ATTACHMENTPOINT: + { + const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(boost::get<S32>(lockSource.second)); + return llformat("Attachment point (%s)", (pAttachPt) ? pAttachPt->getName().c_str() : "Unknown"); + } + case RlvFolderLocks::ST_FOLDER: + { + return "Folder: <todo>"; + } + case RlvFolderLocks::ST_ROOTFOLDER: + { + return "Root folder"; + } + case RlvFolderLocks::ST_SHAREDPATH: + { + const std::string& strPath = boost::get<std::string>(lockSource.second); + return llformat("Shared path (#RLV%s%s)", (!strPath.empty()) ? "/" : "", strPath.c_str()); + } + case RlvFolderLocks::ST_WEARABLETYPE: + { + const std::string& strTypeName = LLWearableType::getTypeName(boost::get<LLWearableType::EType>(lockSource.second)); + return llformat("Wearable type (%s)", strTypeName.c_str()); + } + default: + { + return "(Unknown)"; + } + } +} + +// ============================================================================ +// RlvFloaterBehaviours member functions +// + +// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onOpen(const LLSD& sdKey) +{ + m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterBehaviours::onCommand, this, _1, _2)); + + refreshAll(); +} + +// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onClose(bool fQuitting) +{ + m_ConnRlvCommand.disconnect(); +} + +// Checked: 2010-04-18 (RLVa-1.3.1c) | Modified: RLVa-1.2.0e +void RlvFloaterBehaviours::onAvatarNameLookup(const LLUUID& idAgent, const LLAvatarName& avName) +{ + uuid_vec_t::iterator itLookup = std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idAgent); + if (itLookup != m_PendingLookup.end()) + m_PendingLookup.erase(itLookup); + if (getVisible()) + refreshAll(); +} + +// static +std::string RlvFloaterBehaviours::getFormattedBehaviourString(ERlvBehaviourFilter eFilter) +{ + std::ostringstream strRestrictions; + + strRestrictions << RlvStrings::getVersion(LLUUID::null) << "\n"; + + for (const auto& rlvObjectEntry : RlvHandler::instance().getObjectMap()) + { + strRestrictions << "\n" << rlvGetItemNameFromObjID(rlvObjectEntry.first) << ":\n"; + for (const RlvCommand& rlvCmd : rlvObjectEntry.second.getCommandList()) + { + bool fIsException = (rlvCmd.hasOption()) && (rlvGetShowException(rlvCmd.getBehaviourType())); + if ( ((ERlvBehaviourFilter::BEHAVIOURS_ONLY == eFilter) && (fIsException)) || + ((ERlvBehaviourFilter::EXCEPTIONS_ONLY == eFilter) && (!fIsException)) ) + { + continue; + } + + std::string strOption; LLUUID idOption; + if ( (rlvCmd.hasOption()) && (idOption.set(rlvCmd.getOption(), FALSE)) && (idOption.notNull()) ) + { + LLAvatarName avName; + if (gObjectList.findObject(idOption)) + strOption = rlvGetItemNameFromObjID(idOption, true); + else if (LLAvatarNameCache::get(idOption, &avName)) + strOption = (!avName.getAccountName().empty()) ? avName.getAccountName() : avName.getDisplayName(); + else if (!gCacheName->getGroupName(idOption, strOption)) + strOption = rlvCmd.getOption(); + } + + strRestrictions << " -> " << rlvCmd.asString(); + if ((!strOption.empty()) && (strOption != rlvCmd.getOption())) + strRestrictions << " [" << strOption << "]"; + strRestrictions << "\n"; + } + } + + return strRestrictions.str(); +} + +// Checked: 2011-05-26 (RLVa-1.3.1c) | Added: RLVa-1.3.1c +void RlvFloaterBehaviours::onBtnCopyToClipboard() +{ + LLWString wstrRestrictions = utf8str_to_wstring(getFormattedBehaviourString(ERlvBehaviourFilter::ALL)); + LLClipboard::instance().copyToClipboard(wstrRestrictions, 0, wstrRestrictions.length()); +} + +// Checked: 2011-05-23 (RLVa-1.3.1c) | Modified: RLVa-1.3.1c +void RlvFloaterBehaviours::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet) +{ + if ( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) ) + refreshAll(); +} + +// Checked: 2011-05-23 (RLVa-1.3.1c) | Added: RLVa-1.3.1c +BOOL RlvFloaterBehaviours::postBuild() +{ + getChild<LLUICtrl>("copy_btn")->setCommitCallback(boost::bind(&RlvFloaterBehaviours::onBtnCopyToClipboard, this)); + return TRUE; +} + +void RlvFloaterBehaviours::refreshAll() +{ + LLCtrlListInterface* pBhvrList = childGetListInterface("behaviour_list"); + LLCtrlListInterface* pExceptList = childGetListInterface("exception_list"); + LLCtrlListInterface* pModifierList = childGetListInterface("modifier_list"); + if ( (!pBhvrList) || (!pExceptList) || (!pModifierList) ) + return; + pBhvrList->operateOnAll(LLCtrlListInterface::OP_DELETE); + pExceptList->operateOnAll(LLCtrlListInterface::OP_DELETE); + pModifierList->operateOnAll(LLCtrlListInterface::OP_DELETE); + + if (!isAgentAvatarValid()) + return; + + // + // Set-up a row we can just reuse + // + LLSD sdBhvrRow; LLSD& sdBhvrColumns = sdBhvrRow["columns"]; + sdBhvrColumns[0] = LLSD().with("column", "behaviour").with("type", "text"); + sdBhvrColumns[1] = LLSD().with("column", "issuer").with("type", "text"); + + LLSD sdExceptRow; LLSD& sdExceptColumns = sdExceptRow["columns"]; + sdExceptColumns[0] = LLSD().with("column", "behaviour").with("type", "text"); + sdExceptColumns[1] = LLSD().with("column", "option").with("type", "text"); + sdExceptColumns[2] = LLSD().with("column", "issuer").with("type", "text"); + + LLSD sdModifierRow; LLSD& sdModifierColumns = sdModifierRow["columns"]; + sdModifierColumns[0] = LLSD().with("column", "modifier").with("type", "text"); + sdModifierColumns[1] = LLSD().with("column", "value").with("type", "text"); + sdModifierColumns[2] = LLSD().with("column", "primary").with("type", "text"); + + // + // List behaviours + // + for (const auto& rlvObjectEntry : RlvHandler::instance().getObjectMap()) + { + const std::string strIssuer = rlvGetItemNameFromObjID(rlvObjectEntry.first); + + for (const RlvCommand& rlvCmd : rlvObjectEntry.second.getCommandList()) + { + std::string strOption; LLUUID idOption; + if ( (rlvCmd.hasOption()) && (idOption.set(rlvCmd.getOption(), FALSE)) && (idOption.notNull()) ) + { + LLAvatarName avName; + if (gObjectList.findObject(idOption)) + { + strOption = rlvGetItemNameFromObjID(idOption, true); + } + else if (LLAvatarNameCache::get(idOption, &avName)) + { + strOption = (!avName.getAccountName().empty()) ? avName.getAccountName() : avName.getDisplayName(); + } + else if (!gCacheName->getGroupName(idOption, strOption)) + { + if (m_PendingLookup.end() == std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idOption)) + { + LLAvatarNameCache::get(idOption, boost::bind(&RlvFloaterBehaviours::onAvatarNameLookup, this, _1, _2)); + m_PendingLookup.push_back(idOption); + } + strOption = rlvCmd.getOption(); + } + } + + if ( (rlvCmd.hasOption()) && (rlvGetShowException(rlvCmd.getBehaviourType())) ) + { + // List under the "Exception" tab + sdExceptRow["enabled"] = gRlvHandler.isException(rlvCmd.getBehaviourType(), idOption); + sdExceptColumns[0]["value"] = rlvCmd.getBehaviour(); + sdExceptColumns[1]["value"] = strOption; + sdExceptColumns[2]["value"] = strIssuer; + pExceptList->addElement(sdExceptRow, ADD_BOTTOM); + } + else + { + // List under the "Restrictions" tab + sdBhvrColumns[0]["value"] = (strOption.empty()) ? rlvCmd.asString() : rlvCmd.getBehaviour() + ":" + strOption; + sdBhvrColumns[1]["value"] = strIssuer; + pBhvrList->addElement(sdBhvrRow, ADD_BOTTOM); + } + } + } + + // + // List modifiers + // + for (int idxModifier = 0; idxModifier < RLV_MODIFIER_COUNT; idxModifier++) + { + const RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().m_BehaviourModifiers[idxModifier]; + if (pBhvrModifier) + { + sdModifierRow["enabled"] = (pBhvrModifier->hasValue()); + sdModifierColumns[0]["value"] = pBhvrModifier->getName(); + + if (pBhvrModifier->hasValue()) + { + const RlvBehaviourModifierValue& modValue = pBhvrModifier->getValue(); + if (typeid(float) == modValue.type()) + sdModifierColumns[1]["value"] = llformat("%f", boost::get<float>(modValue)); + else if (typeid(int) == modValue.type()) + sdModifierColumns[1]["value"] = llformat("%d", boost::get<int>(modValue)); + else if (typeid(bool) == modValue.type()) + sdModifierColumns[1]["value"] = (boost::get<bool>(modValue)) ? "true" : "false"; + else if (typeid(LLUUID) == modValue.type()) + sdModifierColumns[1]["value"] = boost::get<LLUUID>(modValue).asString(); + } + else + { + sdModifierColumns[1]["value"] = "(default)"; + } + + sdModifierColumns[2]["value"] = (pBhvrModifier->getPrimaryObject().notNull()) ? rlvGetItemNameFromObjID(pBhvrModifier->getPrimaryObject()) : LLStringUtil::null; + pModifierList->addElement(sdModifierRow, ADD_BOTTOM); + } + } +} + +// ============================================================================ +// RlvFloaterLocks member functions +// + +// Checked: 2010-03-11 (RLVa-1.2.0) +void RlvFloaterLocks::onOpen(const LLSD& sdKey) +{ + m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterLocks::onRlvCommand, this, _1, _2)); + + refreshAll(); +} + +// Checked: 2010-03-11 (RLVa-1.2.0) +void RlvFloaterLocks::onClose(bool fQuitting) +{ + m_ConnRlvCommand.disconnect(); +} + +// Checked: 2012-07-14 (RLVa-1.4.7) +BOOL RlvFloaterLocks::postBuild() +{ + getChild<LLUICtrl>("refresh_btn")->setCommitCallback(boost::bind(&RlvFloaterLocks::refreshAll, this)); + + return TRUE; +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvFloaterLocks::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet) +{ + // Refresh on any successful @XXX=y|n command where XXX is any of the attachment or wearable locking behaviours + if ( (RLV_RET_SUCCESS == eRet) && ((RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType())) ) + { + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_DETACH: + case RLV_BHVR_ADDATTACH: + case RLV_BHVR_REMATTACH: + case RLV_BHVR_ADDOUTFIT: + case RLV_BHVR_REMOUTFIT: + refreshAll(); + break; + default: + break; + } + } +} + +// Checked: 2010-03-18 (RLVa-1.2.0) +void RlvFloaterLocks::refreshAll() +{ + LLScrollListCtrl* pLockList = getChild<LLScrollListCtrl>("lock_list"); + pLockList->operateOnAll(LLCtrlListInterface::OP_DELETE); + + if (!isAgentAvatarValid()) + return; + + // + // Set-up a row we can just reuse + // + LLSD sdRow; + LLSD& sdColumns = sdRow["columns"]; + sdColumns[0]["column"] = "lock_type"; sdColumns[0]["type"] = "text"; + sdColumns[1]["column"] = "lock_addrem"; sdColumns[1]["type"] = "text"; + sdColumns[2]["column"] = "lock_target"; sdColumns[2]["type"] = "text"; + sdColumns[3]["column"] = "lock_origin"; sdColumns[3]["type"] = "text"; + + // + // List attachment locks + // + sdColumns[0]["value"] = "Attachment"; + sdColumns[1]["value"] = "rem"; + + const RlvAttachmentLocks::rlv_attachobjlock_map_t& attachObjRem = gRlvAttachmentLocks.getAttachObjLocks(); + for (RlvAttachmentLocks::rlv_attachobjlock_map_t::const_iterator itAttachObj = attachObjRem.begin(); + itAttachObj != attachObjRem.end(); ++itAttachObj) + { + sdColumns[2]["value"] = rlvGetItemNameFromObjID(itAttachObj->first); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachObj->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + // + // List attachment point locks + // + sdColumns[0]["value"] = "Attachment Point"; + + sdColumns[1]["value"] = "add"; + const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtAdd = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_ADD); + for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtAdd.begin(); + itAttachPt != attachPtAdd.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL); + sdColumns[2]["value"] = pAttachPt->getName(); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + sdColumns[1]["value"] = "rem"; + const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtRem = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_REMOVE); + for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtRem.begin(); + itAttachPt != attachPtRem.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL); + sdColumns[2]["value"] = pAttachPt->getName(); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + // + // List wearable type locks + // + sdColumns[0]["value"] = "Wearable Type"; + + sdColumns[1]["value"] = "add"; + const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeAdd = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_ADD); + for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeAdd.begin(); + itWearableType != wearableTypeAdd.end(); ++itWearableType) + { + sdColumns[2]["value"] = LLWearableType::getTypeLabel(itWearableType->first); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + sdColumns[1]["value"] = "rem"; + const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeRem = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_REMOVE); + for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeRem.begin(); + itWearableType != wearableTypeRem.end(); ++itWearableType) + { + sdColumns[2]["value"] = LLWearableType::getTypeName(itWearableType->first); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + + // + // List "nostrip" (soft) locks + // + sdColumns[1]["value"] = "nostrip"; + sdColumns[3]["value"] = "(Agent)"; + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLFindWearablesEx f(true, true); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, FALSE, f); + + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (!RlvForceWear::instance().isStrippable(pItem->getUUID())) + { + sdColumns[0]["value"] = rlvGetItemType(pItem); + sdColumns[2]["value"] = rlvGetItemName(pItem); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + } + + // + // List folder locks + // + { + // Folder lock descriptors + const RlvFolderLocks::folderlock_list_t& folderLocks = RlvFolderLocks::instance().getFolderLocks(); + for (RlvFolderLocks::folderlock_list_t::const_iterator itFolderLock = folderLocks.begin(); + itFolderLock != folderLocks.end(); ++itFolderLock) + { + const RlvFolderLocks::folderlock_descr_t* pLockDescr = *itFolderLock; + if (pLockDescr) + { + sdColumns[0]["value"] = "Folder Descriptor"; + sdColumns[1]["value"] = + rlvLockMaskToString(pLockDescr->eLockType) + "/" + + rlvFolderLockPermissionToString(pLockDescr->eLockPermission) + "/" + + rlvFolderLockScopeToString(pLockDescr->eLockScope); + sdColumns[2]["value"] = rlvFolderLockSourceToTarget(pLockDescr->lockSource); + sdColumns[3]["value"] = rlvGetItemNameFromObjID(pLockDescr->idRlvObj); + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + } + } + + { + // Folder locked attachments and wearables + uuid_vec_t idItems; + const uuid_vec_t& folderLockAttachmentsIds = RlvFolderLocks::instance().getAttachmentLookups(); + idItems.insert(idItems.end(), folderLockAttachmentsIds.begin(), folderLockAttachmentsIds.end()); + const uuid_vec_t& folderLockWearabels = RlvFolderLocks::instance().getWearableLookups(); + idItems.insert(idItems.end(), folderLockWearabels.begin(), folderLockWearabels.end()); + + for (uuid_vec_t::const_iterator itItemId = idItems.begin(); itItemId != idItems.end(); ++itItemId) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(*itItemId); + if (pItem) + { + sdColumns[0]["value"] = rlvGetItemType(pItem); + sdColumns[1]["value"] = rlvLockMaskToString(RLV_LOCK_REMOVE); + sdColumns[2]["value"] = rlvGetItemName(pItem); + sdColumns[3]["value"] = "<Folder Lock>"; + + pLockList->addElement(sdRow, ADD_BOTTOM); + } + } + } +} + +// ============================================================================ +// RlvFloaterStrings member functions +// + +// Checked: 2011-11-08 (RLVa-1.5.0) +RlvFloaterStrings::RlvFloaterStrings(const LLSD& sdKey) + : LLFloater(sdKey) + , m_fDirty(false) + , m_pStringList(NULL) +{ +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +BOOL RlvFloaterStrings::postBuild() +{ + // Set up the UI controls + m_pStringList = findChild<LLComboBox>("string_list"); + m_pStringList->setCommitCallback(boost::bind(&RlvFloaterStrings::checkDirty, this, true)); + + LLUICtrl* pDefaultBtn = findChild<LLUICtrl>("default_btn"); + pDefaultBtn->setCommitCallback(boost::bind(&RlvFloaterStrings::onStringRevertDefault, this)); + + // Read all string metadata from the default strings file + llifstream fileStream(RlvStrings::getStringMapPath().c_str(), std::ios::binary); LLSD sdFileData; + if ( (fileStream.is_open()) && (LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) ) + { + m_sdStringsInfo = sdFileData["strings"]; + fileStream.close(); + } + + // Populate the combo box + for (LLSD::map_const_iterator itString = m_sdStringsInfo.beginMap(); itString != m_sdStringsInfo.endMap(); ++itString) + { + const LLSD& sdStringInfo = itString->second; + if ( (!sdStringInfo.has("customizable")) || (!sdStringInfo["customizable"].asBoolean()) ) + continue; + m_pStringList->add( (sdStringInfo.has("label")) ? sdStringInfo["label"].asString() : itString->first, itString->first); + } + + refresh(); + + return TRUE; +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::onClose(bool fQuitting) +{ + checkDirty(false); + if (m_fDirty) + { + // Save the custom string overrides + RlvStrings::saveToFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE)); + + // Remind the user their changes require a relog to take effect + LLNotificationsUtil::add("RLVaChangeStrings"); + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::onStringRevertDefault() +{ + if (!m_strStringCurrent.empty()) + { + RlvStrings::setCustomString(m_strStringCurrent, LLStringUtil::null); + m_fDirty = true; + } + refresh(); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::checkDirty(bool fRefresh) +{ + LLTextEditor* pStringValue = findChild<LLTextEditor>("string_value"); + if (!pStringValue->isPristine()) + { + RlvStrings::setCustomString(m_strStringCurrent, pStringValue->getText()); + m_fDirty = true; + } + + if (fRefresh) + { + refresh(); + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvFloaterStrings::refresh() +{ + m_strStringCurrent = (-1 != m_pStringList->getCurrentIndex()) ? m_pStringList->getSelectedValue().asString() : LLStringUtil::null; + + LLTextEditor* pStringDescr = findChild<LLTextEditor>("string_descr"); + pStringDescr->clear(); + LLTextEditor* pStringValue = findChild<LLTextEditor>("string_value"); + pStringValue->setEnabled(!m_strStringCurrent.empty()); + pStringValue->clear(); + if (!m_strStringCurrent.empty()) + { + if (m_sdStringsInfo[m_strStringCurrent].has("description")) + pStringDescr->setText(m_sdStringsInfo[m_strStringCurrent]["description"].asString()); + pStringValue->setText(RlvStrings::getString(m_strStringCurrent)); + pStringValue->makePristine(); + } + + findChild<LLUICtrl>("default_btn")->setEnabled(!m_strStringCurrent.empty()); +} + +// ============================================================================ +// RlvFloaterConsole +// + +static const char s_strRlvConsolePrompt[] = "> "; +static const char s_strRlvConsoleDisabled[] = "RLVa is disabled"; +static const char s_strRlvConsoleInvalid[] = "Invalid command"; + +RlvFloaterConsole::RlvFloaterConsole(const LLSD& sdKey) + : LLFloater(sdKey), m_pOutputText(nullptr) +{ +} + +RlvFloaterConsole::~RlvFloaterConsole() +{ +} + +BOOL RlvFloaterConsole::postBuild() +{ + LLLineEditor* pInputEdit = getChild<LLLineEditor>("console_input"); + pInputEdit->setEnableLineHistory(true); + pInputEdit->setCommitCallback(boost::bind(&RlvFloaterConsole::onInput, this, _1, _2)); + pInputEdit->setFocus(true); + pInputEdit->setCommitOnFocusLost(false); + + m_pOutputText = getChild<LLTextEditor>("console_output"); + m_pOutputText->appendText(s_strRlvConsolePrompt, false); + + return TRUE; +} + +void RlvFloaterConsole::onClose(bool fQuitting) +{ + RlvBehaviourDictionary::instance().clearModifiers(gAgent.getID()); + gRlvHandler.processCommand(gAgent.getID(), "clear", true); +} + +void RlvFloaterConsole::addCommandReply(const std::string& strCommand, const std::string& strReply) +{ + m_pOutputText->appendText(llformat("%s: ", strCommand.c_str()), true); + m_pOutputText->appendText(strReply, false); +} + +void RlvFloaterConsole::onInput(LLUICtrl* pCtrl, const LLSD& sdParam) +{ + LLLineEditor* pInputEdit = static_cast<LLLineEditor*>(pCtrl); + std::string strInput = pInputEdit->getText(); + LLStringUtil::trim(strInput); + + m_pOutputText->appendText(strInput, false); + pInputEdit->clear(); + + if (!rlv_handler_t::isEnabled()) + { + m_pOutputText->appendText(s_strRlvConsoleDisabled, true); + } + else if ( (strInput.length() <= 3) || (RLV_CMD_PREFIX != strInput[0]) ) + { + m_pOutputText->appendText(s_strRlvConsoleInvalid, true); + } + else + { + strInput.erase(0, 1); + LLStringUtil::toLower(strInput); + + std::string strExecuted, strFailed, strRetained, *pstr; + + boost_tokenizer tokens(strInput, boost::char_separator<char>(",", "", boost::drop_empty_tokens)); + for (std::string strCmd : tokens) + { + ERlvCmdRet eRet = gRlvHandler.processCommand(gAgent.getID(), strCmd, true); + if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) ) + pstr = &strExecuted; + else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) ) + pstr = &strFailed; + else if (RLV_RET_RETAINED == eRet) + pstr = &strRetained; + else + { + RLV_ASSERT(false); + pstr = &strFailed; + } + + if (const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet)) + strCmd.append(" (").append(pstrSuffix).append(")"); + else if (RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS)) + strCmd.clear(); // Only show feedback on successful commands when there's an informational notice + + if (!pstr->empty()) + pstr->push_back(','); + pstr->append(strCmd); + } + + if (!strExecuted.empty()) + m_pOutputText->appendText("INFO: @" + strExecuted, true); + if (!strFailed.empty()) + m_pOutputText->appendText("ERR: @" + strFailed, true); + if (!strRetained.empty()) + m_pOutputText->appendText("RET: @" + strRetained, true); + + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + } + + m_pOutputText->appendText(s_strRlvConsolePrompt, true); +} + +// ============================================================================ diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h new file mode 100644 index 0000000000000000000000000000000000000000..f29fa92483d3e24ab1a700f8be33670e521f81da --- /dev/null +++ b/indra/newview/rlvfloaters.h @@ -0,0 +1,170 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_FLOATERS_H +#define RLV_FLOATERS_H + +#include "llfloater.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// Foward declarations +// +class LLComboBox; +class LLTextEditor; + +// ============================================================================ +// RlvFloaterLocks class declaration +// + +enum class ERlvBehaviourFilter { + BEHAVIOURS_ONLY, + EXCEPTIONS_ONLY, + ALL +}; + +class RlvFloaterBehaviours : public LLFloater +{ + friend class LLFloaterReg; +private: + RlvFloaterBehaviours(const LLSD& sdKey) : LLFloater(sdKey) {} + + /* + * LLFloater overrides + */ +public: + /*virtual*/ void onOpen(const LLSD& sdKey); + /*virtual*/ void onClose(bool fQuitting); + /*virtual*/ BOOL postBuild(); + + /* + * Member functions + */ + static std::string getFormattedBehaviourString(ERlvBehaviourFilter eFilter); +protected: + void onAvatarNameLookup(const LLUUID& idAgent, const LLAvatarName& avName); + void onBtnCopyToClipboard(); + void onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet); + void refreshAll(); + + /* + * Member variables + */ +protected: + boost::signals2::connection m_ConnRlvCommand; + uuid_vec_t m_PendingLookup; +}; + +// ============================================================================ +// RlvFloaterLocks class declaration +// + +class RlvFloaterLocks : public LLFloater +{ + friend class LLFloaterReg; +private: + RlvFloaterLocks(const LLSD& sdKey) : LLFloater(sdKey) {} + + /* + * LLFloater overrides + */ +public: + /*virtual*/ void onOpen(const LLSD& sdKey); + /*virtual*/ void onClose(bool fQuitting); + /*virtual*/ BOOL postBuild(); + + /* + * Member functions + */ +protected: + void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet); + void refreshAll(); + + /* + * Member variables + */ +protected: + boost::signals2::connection m_ConnRlvCommand; +}; + +// ============================================================================ +// RlvFloaterStrings class declaration +// + +class RlvFloaterStrings : public LLFloater +{ + friend class LLFloaterReg; +private: + RlvFloaterStrings(const LLSD& sdKey); + + // LLFloater overrides +public: + /*virtual*/ void onClose(bool fQuitting); + /*virtual*/ BOOL postBuild(); + + // Member functions +protected: + void onStringRevertDefault(); + void checkDirty(bool fRefresh); + void refresh(); + + // Member variables +protected: + bool m_fDirty; + std::string m_strStringCurrent; + LLComboBox* m_pStringList; + LLSD m_sdStringsInfo; +}; + +// ============================================================================ +// RlvFloaterConsole - debug console to allow command execution without the need for a script +// + +class RlvFloaterConsole : public LLFloater +{ + friend class LLFloaterReg; + template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl; + friend class RlvHandler; +private: + RlvFloaterConsole(const LLSD& sdKey); + ~RlvFloaterConsole() override; + + /* + * LLFloater overrides + */ +public: + BOOL postBuild() override; + void onClose(bool fQuitting) override; + + /* + * Member functions + */ +protected: + void addCommandReply(const std::string& strCommand, const std::string& strReply); + void onInput(LLUICtrl* ctrl, const LLSD& param); + + /* + * Member variables + */ +protected: + LLTextEditor* m_pOutputText; +}; + +// ============================================================================ + +#endif // RLV_FLOATERS_H diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db9e182b83c6b4931020c6d0e096d218ee31633e --- /dev/null +++ b/indra/newview/rlvhandler.cpp @@ -0,0 +1,3675 @@ +/** + * + * Copyright (c) 2009-2018, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +// Generic includes +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llappearancemgr.h" +#include "llappviewer.h" +#include "llexperiencecache.h" +#include "llexperiencelog.h" +#include "llgroupactions.h" +#include "llhudtext.h" +#include "llmoveview.h" +#include "llslurl.h" +#include "llstartup.h" +#include "llviewermessage.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +// Command specific includes +#include "llagentcamera.h" // @setcam and related +#include "llavataractions.h" // @stopim IM query +#include "llavatarnamecache.h" // @shownames +#include "llavatarlist.h" // @shownames +#include "llenvmanager.h" // @setenv +#include "llfloatersidepanelcontainer.h"// @shownames +#include "llnotifications.h" // @list IM query +#include "llnotificationsutil.h" +#include "lloutfitslist.h" // @showinv - "Appearance / My Outfits" panel +#include "llpaneloutfitsinventory.h" // @showinv - "Appearance" floater +#include "llpanelpeople.h" // @shownames +#include "llpanelwearing.h" // @showinv - "Appearance / Current Outfit" panel +#include "llregionhandle.h" // @tpto +#include "llsidepanelappearance.h" // @showinv - "Appearance / Edit appearance" panel +#include "lltabcontainer.h" // @showinv - Tab container control for inventory tabs +#include "lltoolmgr.h" // @edit +#include "llviewercamera.h" // @setcam and related +#include "llworldmapmessage.h" // @tpto +#include "llviewertexturelist.h" // @setcam_texture +#include "llviewerwindow.h" // @setoverlay + +// RLVa includes +#include "rlvactions.h" +#include "rlvfloaters.h" +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvhelper.h" +#include "rlvinventory.h" +#include "rlvlocks.h" +#include "rlvmodifiers.h" +#include "rlvui.h" +#include "rlvextensions.h" + +// Boost includes +#include <boost/algorithm/string.hpp> + +// ============================================================================ +// Static variable initialization +// + +bool RlvHandler::m_fEnabled = false; + +rlv_handler_t gRlvHandler; + +// ============================================================================ +// Command specific helper functions +// + +// Checked: 2009-08-04 (RLVa-1.0.1d) | Added: RLVa-1.0.1d +static bool rlvParseNotifyOption(const std::string& strOption, S32& nChannel, std::string& strFilter) +{ + boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens)); + boost_tokenizer::const_iterator itTok = tokens.begin(); + + // Extract and sanity check the first token (required) which is the channel + if ( (itTok == tokens.end()) || (!LLStringUtil::convertToS32(*itTok, nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel)) ) + return false; + + // Second token (optional) is the filter + strFilter.clear(); + if (++itTok != tokens.end()) + { + strFilter = *itTok; + ++itTok; + } + + return (itTok == tokens.end()); +} + +// Checked: 2014-02-26 (RLVa-1.4.10) +static bool rlvParseGetStatusOption(const std::string& strOption, std::string& strFilter, std::string& strSeparator) +{ + // @getstatus:[<option>][;<separator>] + // * Parameters: first and second parameters are both optional + // * Examples : @getstatus=123 ; @getstatus:tp=123 ; @getstatus:tp;|=123 ; @getstatus:;|=123 + + boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens)); + boost_tokenizer::const_iterator itTok = tokens.begin(); + + strSeparator = "/"; + strFilter.clear(); + + // <option> optional parameter (defaults to empty string if unspecified) + if (itTok != tokens.end()) + strFilter = *itTok++; + else + strFilter.clear(); + + // <separator> optional paramter (defaults to '/' if unspecified) + if ( (itTok != tokens.end()) && (!(*itTok).empty()) ) + strSeparator = *itTok++; + else + strSeparator = "/"; + + return true; +} + +// ============================================================================ +// Constructor/destructor +// + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d +RlvHandler::RlvHandler() : m_fCanCancelTp(true), m_posSitSource(), m_pGCTimer(NULL) +{ + gAgent.addListener(this, "new group"); + + // Array auto-initialization to 0 is still not supported in VS2013 + memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); +} + +RlvHandler::~RlvHandler() +{ + gAgent.removeListener(this); + if (m_PendingGroupChange.first.notNull()) + { + LLGroupMgr::instance().removeObserver(m_PendingGroupChange.first, this); + m_PendingGroupChange = std::make_pair(LLUUID::null, LLStringUtil::null); + } + + //delete m_pGCTimer; // <- deletes itself +} + +// ============================================================================ +// Behaviour related functions +// + +bool RlvHandler::findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const +{ + lObjects.clear(); + for (const auto& objEntry : m_Objects) + if (objEntry.second.hasBehaviour(eBhvr, false)) + lObjects.push_back(&objEntry.second); + return !lObjects.empty(); +} + +bool RlvHandler::hasBehaviour(const LLUUID& idRlvObj, ERlvBehaviour eBhvr, const std::string& strOption) const +{ + rlv_object_map_t::const_iterator itObj = m_Objects.find(idRlvObj); + if (m_Objects.end() != itObj) + return itObj->second.hasBehaviour(eBhvr, strOption, false); + return false; +} + +bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const +{ + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + if ( (idObj != itObj->second.getObjectID()) && (itObj->second.hasBehaviour(eBhvr, strOption, false)) ) + return true; + return false; +} + +// Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h +bool RlvHandler::hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption) const +{ + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + if ( (idObjRoot == itObj->second.getRootID()) && (itObj->second.hasBehaviour(eBhvr, strOption, false)) ) + return true; + return false; +} + +bool RlvHandler::ownsBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr) const +{ + bool fHasBhvr = false; + for (const auto& objEntry : m_Objects) + { + if (objEntry.second.hasBehaviour(eBhvr, false)) + { + if (objEntry.first != idObj) + return false; + fHasBhvr = true; + } + } + return fHasBhvr; +} + +// ============================================================================ +// Behaviour exception handling +// + +// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +void RlvHandler::addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption) +{ + m_Exceptions.insert(std::pair<ERlvBehaviour, RlvException>(eBhvr, RlvException(idObj, eBhvr, varOption))); +} + +// Checked: 2009-10-04 (RLVa-1.0.4c) | Modified: RLVa-1.0.4c +bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck) const +{ + // We need to "strict check" exceptions only if: the restriction is actually in place *and* (isPermissive(eBhvr) == FALSE) + if (RLV_CHECK_DEFAULT == typeCheck) + typeCheck = ( (hasBehaviour(eBhvr)) && (!isPermissive(eBhvr)) ) ? RLV_CHECK_STRICT : RLV_CHECK_PERMISSIVE; + + uuid_vec_t objList; + if (RLV_CHECK_STRICT == typeCheck) + { + // If we're "strict checking" then we need the UUID of every object that currently has 'eBhvr' restricted + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + if (itObj->second.hasBehaviour(eBhvr, !hasBehaviour(RLV_BHVR_PERMISSIVE))) + objList.push_back(itObj->first); + } + + for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(eBhvr), + endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException) + { + if (itException->second.varOption == varOption) + { + // For permissive checks we just return on the very first match + if (RLV_CHECK_PERMISSIVE == typeCheck) + return true; + + // For strict checks we don't return until the list is empty (every object with 'eBhvr' restricted also contains the exception) + uuid_vec_t::iterator itList = std::find(objList.begin(), objList.end(), itException->second.idObject); + if (itList != objList.end()) + objList.erase(itList); + if (objList.empty()) + return true; + } + } + return false; +} + +// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +bool RlvHandler::isPermissive(ERlvBehaviour eBhvr) const +{ + return (RlvBehaviourDictionary::instance().getHasStrict(eBhvr)) + ? !((hasBehaviour(RLV_BHVR_PERMISSIVE)) || (isException(RLV_BHVR_PERMISSIVE, eBhvr, RLV_CHECK_PERMISSIVE))) + : true; +} + +// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a +void RlvHandler::removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption) +{ + for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(eBhvr), + endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException) + { + if ( (itException->second.idObject == idObj) && (itException->second.varOption == varOption) ) + { + m_Exceptions.erase(itException); + break; + } + } +} + +// ============================================================================ +// Blocked object handling +// + +void RlvHandler::addBlockedObject(const LLUUID& idObj, const std::string& strName) +{ + m_BlockedObjects.push_back(std::make_tuple(idObj, strName, LLTimer::getTotalSeconds())); +} + +bool RlvHandler::hasUnresolvedBlockedObject() const +{ + return std::any_of(m_BlockedObjects.begin(), m_BlockedObjects.end(), [](const rlv_blocked_object_t& entry) { return std::get<0>(entry).isNull(); }); +} + +bool RlvHandler::isBlockedObject(const LLUUID& idObj) const +{ + return std::any_of(m_BlockedObjects.begin(), m_BlockedObjects.end(), [&idObj](const rlv_blocked_object_t& entry) { return std::get<0>(entry) == idObj; }); +} + +void RlvHandler::removeBlockedObject(const LLUUID& idObj) +{ + m_BlockedObjects.erase(std::remove_if(m_BlockedObjects.begin(), m_BlockedObjects.end(), + [&idObj](const rlv_blocked_object_t& entry) { + return (idObj.notNull()) ? std::get<0>(entry) == idObj : false; + }), m_BlockedObjects.end()); +} + +void RlvHandler::getAttachmentResourcesCoro(const std::string& strUrl) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("RlvHandler::getAttachmentResourcesCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + const LLSD sdResult = httpAdapter->getAndSuspend(httpRequest, strUrl); + + const LLCore::HttpStatus httpStatus = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(sdResult[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]); + if ( (httpStatus) && (sdResult.has("attachments")) ) + { + const LLSD& sdAttachments = sdResult["attachments"]; + for (LLSD::array_const_iterator itAttach = sdAttachments.beginArray(), endAttach = sdAttachments.endArray(); itAttach != endAttach; ++itAttach) + { + if (!itAttach->has("objects")) + continue; + + const LLSD& sdAttachObjects = itAttach->get("objects"); + for (LLSD::array_const_iterator itAttachObj = sdAttachObjects.beginArray(), endAttachObj = sdAttachObjects.endArray(); itAttachObj != endAttachObj; ++itAttachObj) + { + const LLUUID idObj = itAttachObj->get("id").asUUID(); + const std::string& strObjName = itAttachObj->get("name").asStringRef(); + + // If it's an attachment, it should be a temporary one (NOTE: we might catch it before it's had a chance to attach) + const LLViewerObject* pObj = gObjectList.findObject(idObj); + if ( (pObj) && ((!pObj->isAttachment()) || (!pObj->isTempAttachment()) || (isBlockedObject(idObj))) ) + continue; + + // Find it by object name + auto itBlockedObj = std::find_if(m_BlockedObjects.begin(), m_BlockedObjects.end(), + [&strObjName](const rlv_blocked_object_t& entry) { + return (std::get<0>(entry).isNull()) && (std::get<1>(entry) == strObjName); + }); + if (m_BlockedObjects.end() != itBlockedObj) + { + std::get<0>(*itBlockedObj) = idObj; + + RLV_INFOS << "Clearing restrictions from blocked object " << idObj.asString() << RLV_ENDL; + processCommand(idObj, "clear", true); + return; + } + } + } + } +} + +// ============================================================================ +// Command processing functions +// + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +void RlvHandler::addCommandHandler(RlvExtCommandHandler* pCmdHandler) +{ + if ( (pCmdHandler) && (std::find(m_CommandHandlers.begin(), m_CommandHandlers.end(), pCmdHandler) == m_CommandHandlers.end()) ) + m_CommandHandlers.push_back(pCmdHandler); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +void RlvHandler::removeCommandHandler(RlvExtCommandHandler* pCmdHandler) +{ + if (pCmdHandler) + m_CommandHandlers.remove(pCmdHandler); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0a +void RlvHandler::clearCommandHandlers() +{ + std::list<RlvExtCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin(); + while (itHandler != m_CommandHandlers.end()) + { + delete *itHandler; + ++itHandler; + } + m_CommandHandlers.clear(); +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +bool RlvHandler::notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const +{ + std::list<RlvExtCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin(); bool fContinue = true; eRet = RLV_RET_UNKNOWN; + while ( (itHandler != m_CommandHandlers.end()) && ((fContinue) || (fNotifyAll)) ) + { + ERlvCmdRet eCmdRet = RLV_RET_UNKNOWN; + if ((fContinue = !((*itHandler)->*f)(rlvCmd, eCmdRet)) == false) + eRet = eCmdRet; + ++itHandler; + } + RLV_ASSERT( (fContinue) || (eRet != RLV_RET_UNKNOWN) ); + return !fContinue; +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::processCommand(const RlvCommand& rlvCmd, bool fFromObj) +{ + RLV_DEBUGS << "[" << rlvCmd.getObjectID() << "]: " << rlvCmd.asString() << RLV_ENDL; + + if ( (isBlockedObject(rlvCmd.getObjectID())) && (RLV_TYPE_REMOVE != rlvCmd.getParamType()) && (RLV_TYPE_CLEAR != rlvCmd.getParamType()) ) + { + RLV_DEBUGS << "\t-> blocked object" << RLV_ENDL; + return RLV_RET_FAILED_BLOCKED; + } + if (!rlvCmd.isValid()) + { + RLV_DEBUGS << "\t-> invalid syntax" << RLV_ENDL; + return RLV_RET_FAILED_SYNTAX; + } + if (rlvCmd.isBlocked()) + { + RLV_DEBUGS << "\t-> blocked command" << RLV_ENDL; + return RLV_RET_FAILED_DISABLED; + } + + // Using a stack for executing commands solves a few problems: + // - if we passed RlvObject::m_idObj for idObj somewhere and process a @clear then idObj points to invalid/cleared memory at the end + // - if command X triggers command Y along the way then getCurrentCommand()/getCurrentObject() still return Y even when finished + m_CurCommandStack.push(&rlvCmd); m_CurObjectStack.push(rlvCmd.getObjectID()); + const LLUUID& idCurObj = m_CurObjectStack.top(); + + ERlvCmdRet eRet = RLV_RET_UNKNOWN; + switch (rlvCmd.getParamType()) + { + case RLV_TYPE_ADD: // Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + { + if ( (m_Behaviours[rlvCmd.getBehaviourType()]) && + ( (RLV_BHVR_SETCAM == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETDEBUG == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETENV == rlvCmd.getBehaviourType()) ) ) + { + // Some restrictions can only be held by one single object to avoid deadlocks + RLV_DEBUGS << "\t- " << rlvCmd.getBehaviour() << " is already set by another object => discarding" << RLV_ENDL; + eRet = RLV_RET_FAILED_LOCK; + break; + } + + rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fAdded = false; + if (itObj != m_Objects.end()) + { + RlvObject& rlvObj = itObj->second; + fAdded = rlvObj.addCommand(rlvCmd); + } + else + { + RlvObject rlvObj(idCurObj); + fAdded = rlvObj.addCommand(rlvCmd); + itObj = m_Objects.insert(std::pair<LLUUID, RlvObject>(idCurObj, rlvObj)).first; + } + + RLV_DEBUGS << "\t- " << ( (fAdded) ? "adding behaviour" : "skipping duplicate" ) << RLV_ENDL; + + if (fAdded) { // If FALSE then this was a duplicate, there's no need to handle those + if (!m_pGCTimer) + m_pGCTimer = new RlvGCTimer(); + eRet = processAddRemCommand(rlvCmd); + if (!RLV_RET_SUCCEEDED(eRet)) + { + RlvCommand rlvCmdRem(rlvCmd, RLV_TYPE_REMOVE); + itObj->second.removeCommand(rlvCmdRem); + } +// notifyBehaviourObservers(rlvCmd, !fFromObj); + } + else + { + eRet = RLV_RET_SUCCESS_DUPLICATE; + } + } + break; + case RLV_TYPE_REMOVE: // Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + { + rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fRemoved = false; + if (itObj != m_Objects.end()) + fRemoved = itObj->second.removeCommand(rlvCmd); + + RLV_DEBUGS << "\t- " << ( (fRemoved) ? "removing behaviour" + : "skipping remove (unset behaviour or unknown object)") << RLV_ENDL; + + if (fRemoved) { // Don't handle non-sensical removes + eRet = processAddRemCommand(rlvCmd); +// notifyBehaviourObservers(rlvCmd, !fFromObj); + + if (0 == itObj->second.m_Commands.size()) + { + RLV_DEBUGS << "\t- command list empty => removing " << idCurObj << RLV_ENDL; + RlvBehaviourDictionary::instance().clearModifiers(idCurObj); + m_Objects.erase(itObj); + } + } + else + { + eRet = RLV_RET_SUCCESS_UNSET; + } + } + break; + case RLV_TYPE_CLEAR: // Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + eRet = processClearCommand(rlvCmd); + break; + case RLV_TYPE_FORCE: // Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + eRet = processForceCommand(rlvCmd); + break; + case RLV_TYPE_REPLY: // Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + eRet = processReplyCommand(rlvCmd); + break; + case RLV_TYPE_UNKNOWN: // Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f + default: + eRet = RLV_RET_FAILED_PARAM; + break; + } + RLV_ASSERT(RLV_RET_UNKNOWN != eRet); + + m_OnCommand(rlvCmd, eRet, !fFromObj); + + RLV_DEBUGS << "\t--> command " << ((eRet & RLV_RET_SUCCESS) ? "succeeded" : "failed") << RLV_ENDL; + + m_CurCommandStack.pop(); m_CurObjectStack.pop(); + return eRet; +} + +// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj) +{ + if (STATE_STARTED != LLStartUp::getStartupState()) + { + m_Retained.push_back(RlvCommand(idObj, strCommand)); + return RLV_RET_RETAINED; + } + return processCommand(RlvCommand(idObj, strCommand), fFromObj); +} + +// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f +void RlvHandler::processRetainedCommands(ERlvBehaviour eBhvrFilter /*=RLV_BHVR_UNKNOWN*/, ERlvParamType eTypeFilter /*=RLV_TYPE_UNKNOWN*/) +{ + rlv_command_list_t::iterator itCmd = m_Retained.begin(), itCurCmd; + while (itCmd != m_Retained.end()) + { + itCurCmd = itCmd++; // Point the loop iterator ahead + + const RlvCommand& rlvCmd = *itCurCmd; + if ( ((RLV_BHVR_UNKNOWN == eBhvrFilter) || (rlvCmd.getBehaviourType() == eBhvrFilter)) && + ((RLV_TYPE_UNKNOWN == eTypeFilter) || (rlvCmd.getParamType() == eTypeFilter)) ) + { + processCommand(rlvCmd, true); + m_Retained.erase(itCurCmd); + } + } +} + +ERlvCmdRet RlvHandler::processClearCommand(const RlvCommand& rlvCmd) +{ + const std::string& strFilter = rlvCmd.getParam(); std::string strCmdRem; + + rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID()); + if (itObj != m_Objects.end()) // No sense in clearing if we don't have any commands for this object + { + const RlvObject& rlvObj = itObj->second; bool fContinue = true; + for (rlv_command_list_t::const_iterator itCmd = rlvObj.m_Commands.begin(), itCurCmd; + ((fContinue) && (itCmd != rlvObj.m_Commands.end())); ) + { + itCurCmd = itCmd++; // Point itCmd ahead so it won't get invalidated if/when we erase a command + + const RlvCommand& rlvCmdRem = *itCurCmd; strCmdRem = rlvCmdRem.asString(); + if ( (strFilter.empty()) || (std::string::npos != strCmdRem.find(strFilter)) ) + { + fContinue = (rlvObj.m_Commands.size() > 1); // rlvObj will become invalid once we remove the last command + processCommand(rlvCmd.getObjectID(), strCmdRem.append("=y"), false); + } + } + } + + // Let our observers know about clear commands + ERlvCmdRet eRet = RLV_RET_SUCCESS; + notifyCommandHandlers(&RlvExtCommandHandler::onClearCommand, rlvCmd, eRet, true); + + return RLV_RET_SUCCESS; // Don't fail clear commands even if the object didn't exist since it confuses people +} + +bool RlvHandler::processIMQuery(const LLUUID& idSender, const std::string& strMessage) +{ + if ("@stopim" == strMessage) + { + // If the user can't start an IM session terminate it (if one is open) - always notify the sender in this case + if (!RlvActions::canStartIM(idSender, true)) + { + RlvUtil::sendBusyMessage(idSender, RlvStrings::getString(RLV_STRING_STOPIM_ENDSESSION_REMOTE)); + if (RlvActions::hasOpenP2PSession(idSender)) + { + LLAvatarActions::endIM(idSender); + RlvUtil::notifyBlocked(RLV_STRING_STOPIM_ENDSESSION_LOCAL, LLSD().with("NAME", LLSLURL("agent", idSender, "about").getSLURLString()), true); + } + return true; + } + + // User can start an IM session so we do nothing - notify and hide it from the user only if IM queries are enabled + if (!RlvSettings::getEnableIMQuery()) + return false; + RlvUtil::sendBusyMessage(idSender, RlvStrings::getString(RLV_STRING_STOPIM_NOSESSION)); + return true; + } + else if (RlvSettings::getEnableIMQuery()) + { + if ("@version" == strMessage) + { + RlvUtil::sendBusyMessage(idSender, RlvStrings::getVersion(LLUUID::null)); + return true; + } + else if ( ("@list" == strMessage) || ("@except" == strMessage) ) + { + LLNotification::Params params; + params.name = "RLVaListRequested"; + params.functor.function(boost::bind(&RlvHandler::onIMQueryListResponse, this, _1, _2)); + params.substitutions = LLSD().with("NAME_LABEL", LLSLURL("agent", idSender, "completename").getSLURLString()).with("NAME_SLURL", LLSLURL("agent", idSender, "about").getSLURLString()); + params.payload = LLSD().with("from_id", idSender).with("command", strMessage); + + class RlvPostponedOfferNotification : public LLPostponedNotification + { + protected: + void modifyNotificationParams() override + { + LLSD substitutions = mParams.substitutions; + substitutions["NAME"] = mName; + mParams.substitutions = substitutions; + } + }; + LLPostponedNotification::add<RlvPostponedOfferNotification>(params, idSender, false); + return true; + } + } + return false; +} + +void RlvHandler::onIMQueryListResponse(const LLSD& sdNotification, const LLSD sdResponse) +{ + const LLUUID idRequester = sdNotification["payload"]["from_id"].asUUID(); + + const int idxOption = LLNotificationsUtil::getSelectedOption(sdNotification, sdResponse); + if ( (idxOption == 0) || (idxOption == 1) ) + { + if (idxOption == 1) + { + if (LLNotificationPtr pNotif = LLNotificationsUtil::find(sdNotification["id"])) + pNotif->setIgnored(true); + } + + const std::string& strCommand = sdNotification["payload"]["command"].asStringRef(); + if ("@list" == strCommand) + { + RlvUtil::sendIMMessage(idRequester, RlvFloaterBehaviours::getFormattedBehaviourString(ERlvBehaviourFilter::BEHAVIOURS_ONLY).append("\n").append(RlvStrings::getString("imquery_list_suffix")), '\n'); + } + else if ("@except" == strCommand) + { + RlvUtil::sendIMMessage(idRequester, RlvFloaterBehaviours::getFormattedBehaviourString(ERlvBehaviourFilter::EXCEPTIONS_ONLY), '\n'); + } + } + else + { + RlvUtil::sendBusyMessage(idRequester, RlvStrings::getString("imquery_list_deny")); + } +} + +// ============================================================================ +// Command specific helper functions - @setgroup +// + +bool RlvHandler::checkActiveGroupThrottle(const LLUUID& idRlvObj) +{ + bool fAllow = m_GroupChangeExpiration.first.checkExpirationAndReset(llmax(RLV_SETGROUP_THROTTLE, 5.f)); + if (fAllow) + { + // (Un)owned expiration resets the last lock owner + m_GroupChangeExpiration.second.setNull(); + } + else if ( (!fAllow) && (m_GroupChangeExpiration.second.isNull()) && (ownsBehaviour(idRlvObj, RLV_BHVR_SETGROUP)) ) + { + // The current lock owner wants to change the active group (title) before the expiration - allow once + m_GroupChangeExpiration.second = idRlvObj; + m_GroupChangeExpiration.first.setTimerExpirySec(llmax(RLV_SETGROUP_THROTTLE, 5.f)); + fAllow = true; + } + return fAllow; +} + +void RlvHandler::changed(const LLUUID& idGroup, LLGroupChange change) +{ + // If we're receiving information about a group we're not interested in, we forgot a removeObserver somewhere + RLV_ASSERT(idGroup == m_PendingGroupChange.first); + + if ( ((GC_ALL == change) || (GC_ROLE_DATA == change)) && (m_PendingGroupChange.first == idGroup) ) + { + LLGroupMgr::instance().removeObserver(m_PendingGroupChange.first, this); + setActiveGroupRole(m_PendingGroupChange.first, m_PendingGroupChange.second); + } +} + +bool RlvHandler::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata) +{ + // NOTE: we'll fire once for every group the user belongs to so we need to manually keep track of changes + static LLUUID s_idLastAgentGroup = LLUUID::null; + if (s_idLastAgentGroup != gAgent.getGroupID()) + { + s_idLastAgentGroup = gAgent.getGroupID(); + onActiveGroupChanged(); + } + return false; +} + +void RlvHandler::onActiveGroupChanged() +{ + // If the user managed to change their active group (= newly joined or created group) we need to reactivate the previous one + if ( (!RlvActions::canChangeActiveGroup()) && (m_idAgentGroup != gAgent.getGroupID()) ) + { + // Make sure they still belong to the group + if ( (m_idAgentGroup.notNull()) && (!gAgent.isInGroup(m_idAgentGroup)) ) + { + m_idAgentGroup.setNull(); + } + + // Notify them about the change + const LLSD sdArgs = LLSD().with("GROUP_SLURL", (m_idAgentGroup.notNull()) ? llformat("secondlife:///app/group/%s/about", m_idAgentGroup.asString().c_str()) : "(none)"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_GROUPCHANGE, sdArgs); + + setActiveGroup(m_idAgentGroup); + } + else + { + m_idAgentGroup = gAgent.getGroupID(); + + // Allowed change - check if we still need to activate a role + if ( (m_PendingGroupChange.first.notNull()) && (m_PendingGroupChange.first == m_idAgentGroup) ) + { + setActiveGroupRole(m_PendingGroupChange.first, m_PendingGroupChange.second); + } + } +} + +void RlvHandler::setActiveGroup(const LLUUID& idGroup) +{ + // If we have an existing observer fpr a different group, remove it + if ( (m_PendingGroupChange.first.notNull()) && (m_PendingGroupChange.first != idGroup) ) + { + LLGroupMgr::instance().removeObserver(m_PendingGroupChange.first, this); + m_PendingGroupChange = std::make_pair(LLUUID::null, LLStringUtil::null); + } + + if (gAgent.getGroupID() != idGroup) + { + // [Copy/paste from LLGroupActions::activate()] + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ActivateGroup); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, idGroup); + gAgent.sendReliableMessage(); + } + m_idAgentGroup = idGroup; +} + +void RlvHandler::setActiveGroupRole(const LLUUID& idGroup, const std::string& strRole) +{ + // Check if we need a group change first + if (gAgent.getGroupID() != idGroup) + { + setActiveGroup(idGroup); + m_PendingGroupChange = std::make_pair(idGroup, strRole); + return; + } + + // Now that we have the correct group, check if we need to request the role information + /*const*/ auto* pGroupData = LLGroupMgr::instance().getGroupData(idGroup); + if ( ((!pGroupData) && (gAgent.isInGroup(idGroup))) || (!pGroupData->isRoleDataComplete()) ) + { + if (m_PendingGroupChange.first.notNull()) + LLGroupMgr::instance().removeObserver(m_PendingGroupChange.first, this); + m_PendingGroupChange = std::make_pair(idGroup, strRole); + LLGroupMgr::instance().addObserver(idGroup, this); + LLGroupMgr::instance().sendGroupRoleDataRequest(idGroup); + return; + } + + // We have everything - activate the requested role (if we can find it) + if (pGroupData) + { + enum class EMatch { None, Partial, Exact } eMatch = EMatch::None; LLUUID idRole; + for (const auto& roleData : pGroupData->mRoles) + { + // NOTE: exact matches take precedence over partial matches; in case of partial matches the last match wins + const std::string& strRoleName = roleData.second->getRoleData().mRoleName; + if (boost::istarts_with(strRoleName, strRole)) + { + idRole = roleData.first; + eMatch = (strRoleName.length() == strRole.length()) ? EMatch::Exact : EMatch::Partial; + if (eMatch == EMatch::Exact) + break; + } + } + + if (eMatch != EMatch::None) + { + RLV_INFOS << "Activating role '" << strRole << "' for group '" << pGroupData->mName << "'" << RLV_ENDL; + LLGroupMgr::getInstance()->sendGroupTitleUpdate(idGroup, idRole); + } + else + { + RLV_INFOS << "Couldn't find role '" << strRole << "' in group '" << pGroupData->mName << "'" << RLV_ENDL; + } + } + + m_PendingGroupChange = std::make_pair(LLUUID::null, LLStringUtil::null); +} + +// ============================================================================ +// Externally invoked event handlers +// + +// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvHandler::onSitOrStand(bool fSitting) +{ + if (rlv_handler_t::isEnabled()) + { + RlvSettings::updateLoginLastLocation(); + } + + if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (!fSitting) && (!m_posSitSource.isExactlyZero()) ) + { + // NOTE: we need to do this due to the way @standtp triggers a forced teleport: + // - when standing we're called from LLVOAvatar::sitDown() which is called from LLVOAvatar::getOffObject() + // -> at the time sitDown() is called the avatar's parent is still the linkset it was sitting on so "isRoot()" on the avatar will + // return FALSE and we will crash in LLVOAvatar::getRenderPosition() when trying to teleport + // -> postponing the teleport until the next idle tick will ensure that everything has all been properly cleaned up + doOnIdleOneTime(boost::bind(RlvUtil::forceTp, m_posSitSource)); + m_posSitSource.setZero(); + } +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvHandler::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + // Assertion - pAttachObj is never NULL always specifies the root + RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) ); + // Sanity check - we need to be called *after* LLViewerJointAttachment::addObject() + RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) ); + if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) ) + return; + + // Check if we already have an RlvObject instance for this object or one of its child prims + for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + { + // Only if we haven't been able to find this object (= attachment that rezzed in) or if it's a rezzed prim attached from in-world + if ( (!itObj->second.m_fLookup) || (!itObj->second.m_idxAttachPt) ) + { + const LLViewerObject* pObj = gObjectList.findObject(itObj->first); + if ( (pObj) && (pObj->getRootEdit()->getID() == pAttachObj->getID()) ) + { + // Reset any lookup information we might have for this object + itObj->second.m_fLookup = true; + itObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj); + itObj->second.m_idRoot = pAttachObj->getID(); + + // We need to check this object for an active "@detach=n" and actually lock it down now that it's been attached somewhere + if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) + gRlvAttachmentLocks.addAttachmentLock(pAttachObj->getID(), itObj->second.getObjectID()); + } + } + } + + // Fetch the inventory item if it isn't already (we need it in case of a reattach-on-detach) and rename it if appropriate + if ( (STATE_STARTED == LLStartUp::getStartupState()) && (gInventory.isInventoryUsable()) ) + { + RlvRenameOnWearObserver* pFetcher = new RlvRenameOnWearObserver(pAttachObj->getAttachmentItemID()); + pFetcher->startFetch(); + if (pFetcher->isFinished()) + pFetcher->done(); + else + gInventory.addObserver(pFetcher); + } +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvHandler::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + // Assertion - pAttachObj is never NULL always specifies the root + RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) ); + // Sanity check - we need to be called *before* LLViewerJointAttachment::removeObject() + RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) ); + if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) ) + return; + + // If the attachment is no longer attached then then the user "Drop"'ed this attachment somehow + if (!pAttachObj->isAttachment()) + { + // Check if we have any RlvObject instances for this object (or any of its child prims) + for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + { + if ( (itObj->second.m_fLookup) && (itObj->second.m_idRoot == pAttachObj->getID()) ) + { + // Clear the attachment point lookup since it's now an in-world prim + itObj->second.m_idxAttachPt = false; + + // If this object has an active "@detach=n" then we need to release the attachment lock since it's no longer attached + if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) + gRlvAttachmentLocks.removeAttachmentLock(pAttachObj->getID(), itObj->second.getObjectID()); + } + } + } + else + { + // If it's still attached then we need to clean up any restrictions this object (or one of its child prims) may still have set + rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj; + while (itObj != m_Objects.end()) + { + itCurObj = itObj++; // @clear will invalidate our iterator so point it ahead now +#ifdef RLV_DEBUG + bool itObj = true; + RLV_ASSERT(itObj); // Little hack to push itObj out of scope and prevent it from being accidentally used below +#endif // RLV_DEBUG + + // NOTE: ObjectKill seems to happen in reverse (child prims are killed before the root is) so we can't use gObjectList here + if (itCurObj->second.m_idRoot == pAttachObj->getID()) + { + RLV_INFOS << "Clearing " << itCurObj->first.asString() << ":" << RLV_ENDL; + processCommand(itCurObj->second.getObjectID(), "clear", true); + RLV_INFOS << "\t-> done" << RLV_ENDL; + } + } + + if (pAttachObj->isTempAttachment()) + { + removeBlockedObject(pAttachObj->getID()); + } + } +} + +void RlvHandler::onExperienceAttach(const LLSD& sdExperience, const std::string& strObjName) +{ + if (!RlvSettings::isAllowedExperience(sdExperience[LLExperienceCache::EXPERIENCE_ID].asUUID(), sdExperience[LLExperienceCache::MATURITY].asInteger())) + { + addBlockedObject(LLUUID::null, strObjName); + + const std::string strUrl = gAgent.getRegionCapability("AttachmentResources"); + if (!strUrl.empty()) + { + LLCoros::instance().launch("RlvHandler::getAttachmentResourcesCoro", boost::bind(&RlvHandler::getAttachmentResourcesCoro, this, strUrl)); + } + } +} + +void RlvHandler::onExperienceEvent(const LLSD& sdEvent) +{ + const int nPermission = sdEvent["Permission"].asInteger(); + switch (nPermission) + { + case 4: // Attach + { + const LLUUID& idExperience = sdEvent["public_id"].asUUID(); + const std::string strObjName = sdEvent["ObjectName"].asString(); + LLExperienceCache::instance().get(idExperience, boost::bind(&RlvHandler::onExperienceAttach, this, _1, strObjName)); + } + break; + default: + break; + } +} + +// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvHandler::onGC() +{ + rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj; + while (itObj != m_Objects.end()) + { + itCurObj = itObj++; // @clear will invalidate our iterator so point it ahead now +#ifdef RLV_DEBUG + bool itObj = true; + RLV_ASSERT(itObj); +#endif // RLV_DEBUG + + // Temporary sanity check + RLV_ASSERT(itCurObj->first == itCurObj->second.getObjectID()); + + const LLViewerObject* pObj = gObjectList.findObject(itCurObj->second.getObjectID()); + if (!pObj) + { + // If the RlvObject once existed in gObjectList and now doesn't then expire it right away + // If the RlvObject never existed in gObjectList and still doesn't then increase its "lookup misses" counter + // but if that reaches 20 (we run every 30 seconds so that's about 10 minutes) then we'll expire it too + if ( (itCurObj->second.m_fLookup) || (++itCurObj->second.m_nLookupMisses > 20) ) + { + RLV_INFOS << "Garbage collecting " << itCurObj->first.asString() << ":" << RLV_ENDL; + processCommand(itCurObj->first, "clear", true); + RLV_INFOS << "\t-> done" << RLV_ENDL; + } + } + else + { + // Assertion: if the GC encounters an RlvObject instance that hasn't existed in gObjectList up until now then + // it has to be a rezzed prim (if it was an attachment then RlvHandler::onAttach() should have caught it) + RLV_ASSERT( (itCurObj->second.m_fLookup) || (!pObj->isAttachment()) ); + if (!itCurObj->second.m_fLookup) + { + RLV_INFOS << "Resolved missing object " << itCurObj->first.asString() << RLV_ENDL; + itCurObj->second.m_fLookup = true; + itCurObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pObj); + itCurObj->second.m_idRoot = pObj->getRootEdit()->getID(); + + // NOTE: the following code should NEVER run (see assertion above), but just to be double-triple safety sure + // -> if it does run it likely means that there's a @detach=n in a *child* prim that we couldn't look up in onAttach() + // -> since RLV doesn't currently support @detach=n from child prims it's actually not such a big deal right now but still + if ( (pObj->isAttachment()) && (itCurObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) ) + gRlvAttachmentLocks.addAttachmentLock(pObj->getID(), itCurObj->second.getObjectID()); + } + } + } + + RLV_ASSERT(gRlvAttachmentLocks.verifyAttachmentLocks()); // Verify that we haven't leaked any attachment locks somehow + + // Clean up pending temp attachments that we were never able to resolve + rlv_blocked_object_list_t::const_iterator itBlocked = m_BlockedObjects.cbegin(), itCurBlocked; + while (itBlocked != m_BlockedObjects.end()) + { + itCurBlocked = itBlocked++; +#ifdef RLV_DEBUG + bool itBlocked = true; + RLV_ASSERT(itBlocked); +#endif // RLV_DEBUG + + const LLUUID& idObj = std::get<0>(*itCurBlocked); + if ( (idObj.notNull()) || (LLTimer::getTotalSeconds() - std::get<2>(*itCurBlocked) < 300.f) ) + continue; + + m_BlockedObjects.erase(itCurBlocked); + } + + return (0 != m_Objects.size()); // GC will kill itself if it has nothing to do +} + +// Checked: 2009-11-26 (RLVa-1.1.0f) | Added: RLVa-1.1.0f +void RlvHandler::onIdleStartup(void* pParam) +{ + LLTimer* pTimer = (LLTimer*)pParam; + if (LLStartUp::getStartupState() < STATE_STARTED) + { + // We don't want to run this *too* often + if ( (LLStartUp::getStartupState() >= STATE_MISC) && (pTimer->getElapsedTimeF32() >= 2.0) ) + { + RlvHandler::instance().processRetainedCommands(RLV_BHVR_VERSION, RLV_TYPE_REPLY); + RlvHandler::instance().processRetainedCommands(RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY); + RlvHandler::instance().processRetainedCommands(RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY); + pTimer->reset(); + } + } + else + { + // Clean-up + gIdleCallbacks.deleteFunction(onIdleStartup, pParam); + delete pTimer; + } +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvHandler::onLoginComplete() +{ + RlvInventory::instance().fetchWornItems(); + RlvInventory::instance().fetchSharedInventory(); + RlvSettings::updateLoginLastLocation(); + + m_ExperienceEventConn = LLExperienceLog::instance().addUpdateSignal(boost::bind(&RlvHandler::onExperienceEvent, this, _1)); + m_TeleportFailedConn = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this)); + m_TeleportFinishedConn = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1)); + + processRetainedCommands(); +} + +void RlvHandler::onTeleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt, const LLUUID& idRlvObj) +{ + if (hRegion) + { + m_CurObjectStack.push(idRlvObj); + + const LLVector3d posGlobal = from_region_handle(hRegion) + (LLVector3d)posRegion; + if (vecLookAt.isExactlyZero()) + gAgent.teleportViaLocation(posGlobal); + else + gAgent.teleportViaLocationLookAt(posGlobal, vecLookAt); + + m_CurObjectStack.pop(); + } +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvHandler::onTeleportFailed() +{ + setCanCancelTp(true); +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d +void RlvHandler::onTeleportFinished(const LLVector3d& posArrival) +{ + setCanCancelTp(true); +} + +// ============================================================================ +// String/chat censoring functions +// + +size_t utf8str_strlen(const std::string& utf8) +{ + const char* pUTF8 = utf8.c_str(); size_t length = 0; + for (int idx = 0, cnt = utf8.length(); idx < cnt ;idx++) + { + // We're looking for characters that don't start with 10 as their high bits + if ((pUTF8[idx] & 0xC0) != 0x80) + length++; + } + return length; +} + +std::string utf8str_chtruncate(const std::string& utf8, size_t length) +{ + if (0 == length) + return std::string(); + if (utf8.length() <= length) + return utf8; + + const char* pUTF8 = utf8.c_str(); int idx = 0; + while ( (pUTF8[idx]) && (length > 0) ) + { + // We're looking for characters that don't start with 10 as their high bits + if ((pUTF8[idx] & 0xC0) != 0x80) + length--; + idx++; + } + + return utf8.substr(0, idx); +} + +// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0f +bool RlvHandler::filterChat(std::string& strUTF8Text, bool fFilterEmote) const +{ + if (strUTF8Text.empty()) + return false; + + bool fFilter = false; + if (RlvUtil::isEmote(strUTF8Text)) // Check if it's an emote + { + if (fFilterEmote) // Emote filtering depends on fFilterEmote + { + if ( (strUTF8Text.find_first_of("\"()*=^_?~") != std::string::npos) || + (strUTF8Text.find(" -") != std::string::npos) || (strUTF8Text.find("- ") != std::string::npos) || + (strUTF8Text.find("''") != std::string::npos) ) + { + fFilter = true; // Emote contains illegal character (or character sequence) + } + else if (!hasBehaviour(RLV_BHVR_EMOTE)) + { + int idx = strUTF8Text.find('.'); // Truncate at 20 characters or at the dot (whichever is shorter) + strUTF8Text = utf8str_chtruncate(strUTF8Text, ( (idx > 0) && (idx < 20) ) ? idx + 1 : 20); + } + } + } + else if (strUTF8Text[0] == '/') // Not an emote, but starts with a '/' + { + fFilter = (utf8str_strlen(strUTF8Text) > 7);// Allow as long if it's 6 characters or less + } + else if ( (!RlvSettings::getCanOOC()) || + (strUTF8Text.length() < 4) || (strUTF8Text.compare(0, 2, "((")) || (strUTF8Text.compare(strUTF8Text.length() - 2, 2, "))")) ) + { + fFilter = true; // Regular chat (not OOC) + } + + if (fFilter) + strUTF8Text = (gSavedSettings.getBOOL("RestrainedLoveShowEllipsis")) ? "..." : ""; + return fFilter; +} + +// Checked: 2010-11-29 (RLVa-1.3.0c) | Added: RLVa-1.3.0c +bool RlvHandler::hasException(ERlvBehaviour eBhvr) const +{ + return (m_Exceptions.find(eBhvr) != m_Exceptions.end()); +} + +// Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a +bool RlvHandler::redirectChatOrEmote(const std::string& strUTF8Text) const +{ + // Sanity check - @redirchat only for chat and @rediremote only for emotes + ERlvBehaviour eBhvr = (!RlvUtil::isEmote(strUTF8Text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE; + if ( (strUTF8Text.empty()) || (!hasBehaviour(eBhvr)) ) + return false; + + if (RLV_BHVR_REDIRCHAT == eBhvr) + { + std::string strText = strUTF8Text; + if (!filterChat(strText, false)) + return false; // @sendchat wouldn't filter it so @redirchat won't redirect it either + } + + for (rlv_exception_map_t::const_iterator itRedir = m_Exceptions.lower_bound(eBhvr), + endRedir = m_Exceptions.upper_bound(eBhvr); itRedir != endRedir; ++itRedir) + { + S32 nChannel = boost::get<S32>(itRedir->second.varOption); + if (RlvActions::canSendChannel(nChannel)) + { + if (!RlvSettings::getSplitRedirectChat()) + RlvUtil::sendChatReply(nChannel, strUTF8Text); + else + RlvUtil::sendChatReplySplit(nChannel, strUTF8Text); + } + } + + return true; +} + +// ============================================================================ +// Composite folders +// + +#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const + { + if (pFolder) + { + // Composite folder naming: ^\.?[Folder] + const std::string& cstrFolder = pFolder->getName(); + std::string::size_type idxStart = cstrFolder.find('['), idxEnd = cstrFolder.find(']', idxStart); + if ( ((0 == idxStart) || (1 == idxStart)) && (idxEnd - idxStart > 1) ) + { + if (pstrName) + pstrName->assign(cstrFolder.substr(idxStart + 1, idxEnd - idxStart - 1)); + return true; + } + } + return false; + } + + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const + { +/* + LLViewerInventoryCategory* pRlvRoot; LLViewerInventoryItem* pItem; + if ( (idItem.notNull()) && ((pRlvRoot = getSharedRoot()) != NULL) && + (gInventory.isObjectDescendentOf(idItem, pRlvRoot->getUUID())) && ((pItem = gInventory.getItem(idItem)) != NULL) ) + { + // We know it's an item in a folder under the shared root (we need its parent if it's a folded folder) + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + if (isFoldedFolder(pFolder, true, false)) // Don't check if the folder is a composite folder + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + + if ( (pFolder) && (getCompositeInfo(pFolder, pstrName)) ) + { + if (ppFolder) + *ppFolder = pFolder; + return true; + } + } +*/ + return false; + } +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + +#ifdef RLV_EXPERIMENTAL_COMPOSITE_FOLDING + // Checked: + inline bool RlvHandler::isHiddenCompositeItem(const LLUUID& idItem, const std::string& cstrItemType) const + { + // An item that's part of a composite folder will be hidden from @getoutfit and @getattach if: + // (1) the composite name specifies either a wearable layer or an attachment point + // (2) the specified wearable layer or attachment point is worn and resides in the folder + // (3) cstrItemType isn't the specified wearable layer or attach point + // + // Example: #RLV/Separates/Shoes/ChiChi Pumps/.[shoes] with items: "Shoe Base", "Shoe (left foot)" and "Shoe (right foot)" + // -> as long as "Shoe Base" is worn, @getattach should not reflect "left foot", nor "right foot" + std::string strComposite; LLViewerInventoryCategory* pFolder; + LLWearableType::EType type; S32 idxAttachPt; + if ( (getCompositeInfo(idItem, &strComposite, &pFolder)) && (cstrItemType != strComposite) ) + { + LLUUID idCompositeItem; + if ((type = LLWearable::typeNameToType(strComposite)) != WT_INVALID) + { + idCompositeItem = gAgent.getWearableItem(type); + } + else if ((idxAttachPt = getAttachPointIndex(strComposite, true)) != 0) + { + LLVOAvatar* pAvatar; LLViewerJointAttachment* pAttachmentPt; + if ( ((pAvatar = gAgent.getAvatarObject()) != NULL) && + ((pAttachmentPt = get_if_there(pAvatar->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL)) != NULL) ) + { + idCompositeItem = pAttachmentPt->getItemID(); + } + } + + if ( (idCompositeItem.notNull()) && (gInventory.isObjectDescendentOf(idCompositeItem, pFolder->getUUID())) ) + return true; + } + return false; + } +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDING + +#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::canTakeOffComposite(const LLInventoryCategory* pFolder) const + { + // Sanity check - if there's no folder or no avatar then there is nothing to take off + LLVOAvatarSelf* pAvatar = gAgent.getAvatarObject(); + if ( (!pFolder) || (!pAvatar) ) + return false; + // Sanity check - if nothing is locked then we can definitely take it off + if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) || + (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE)) ) + { + return true; + } + +/* + LLInventoryModel::cat_array_t folders; + LLInventoryModel::item_array_t items; + RlvWearableItemCollector functor(pFolder->getUUID(), true, false); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor); + + for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = items.get(idxItem); + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + { + LLWearable* pWearable = gAgent.getWearableFromWearableItem(pItem->getUUID()); + if ( (pWearable) && (!isRemovable(pWearable->getType())) ) + return false; // If one wearable in the folder is non-removeable then the entire folder should be + } + break; + case LLAssetType::AT_OBJECT: + { + LLViewerObject* pObj = pAvatar->getWornAttachment(pItem->getUUID()); + if ( (pObj != NULL) && (isLockedAttachment(pObj, RLV_LOCK_REMOVE)) ) + return false; // If one attachment in the folder is non-detachable then the entire folder should be + } + break; + default: + break; + } + } +*/ + return true; + } + + // Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i + bool RlvHandler::canWearComposite(const LLInventoryCategory* pFolder) const + { + // Sanity check - if there's no folder or no avatar then there is nothing to wear + LLVOAvatar* pAvatar = gAgent.getAvatarObject(); + if ( (!pFolder) || (!pAvatar) ) + return false; + // Sanity check - if nothing is locked then we can definitely wear it + if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (!gRlvWearableLocks.hacLockedWearableType(RLV_LOCK_ANY)) ) + return true; + +/* + LLInventoryModel::cat_array_t folders; + LLInventoryModel::item_array_t items; + RlvWearableItemCollector functor(pFolder->getUUID(), true, false); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor); + + for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.get(idxItem); + + if (RlvForceWear::isWearingItem(pItem)) + continue; // Don't examine any items we're already wearing + + // A wearable layer or attachment point: + // - can't be "add locked" + // - can't be worn and "remove locked" + // - can't be worn and have its item belong to a *different* composite folder that we can't take off + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + { + // NOTE: without its asset we don't know what type the wearable is so we need to look at the item's flags instead + LLWearableType::EType wtType = (LLWearableType::EType)(pItem->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); + LLViewerInventoryCategory* pFolder; + if ( (!isWearable(wtType)) || + ( (gAgent.getWearable(wtType)) && (!isRemovable(wtType)) ) || + ( (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) && + (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) ) + { + return false; + } + } + break; + case LLAssetType::AT_OBJECT: + { + // If we made it here then *something* is add/remove locked so we absolutely need to know its attachment point + LLViewerJointAttachment* pAttachPt = getAttachPoint(pItem, true); + LLViewerInventoryCategory* pFolder; + if ( (!pAttachPt) || (isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) || + ( (pAttachPt->getObject()) && (isLockedAttachment(pAttachPt, RLV_LOCK_REMOVE)) ) || + ( (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) && + (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) ) + { + return false; + } + } + break; + default: + break; + } + } +*/ + return true; + } +#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + +// ============================================================================ +// Initialization helper functions +// + +bool RlvHandler::canEnable() +{ + return LLStartUp::getStartupState() <= STATE_LOGIN_CLEANUP; +} + +bool RlvHandler::setEnabled(bool fEnable) +{ + if (m_fEnabled == fEnable) + return fEnable; + + if ( (fEnable) && (canEnable()) ) + { + RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersionAbout() << RLV_ENDL; + m_fEnabled = true; + + // Initialize static classes + RlvSettings::initClass(); + RlvStrings::initClass(); + + RlvHandler::instance().addCommandHandler(new RlvExtGetSet()); + + // Make sure we get notified when login is successful + if (LLStartUp::getStartupState() < STATE_STARTED) + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&RlvHandler::onLoginComplete, RlvHandler::getInstance())); + else + RlvHandler::instance().onLoginComplete(); + + // Set up RlvUIEnabler + RlvUIEnabler::getInstance(); + + // Reset to show assertions if the viewer version changed + if (gSavedSettings.getString("LastRunVersion") != gLastRunVersion) + gSavedSettings.setBOOL("RLVaShowAssertionFailures", TRUE); + } + + return m_fEnabled; +} + +// ============================================================================ +// Command handlers (RLV_TYPE_ADD and RLV_TYPE_REMOVE) +// + +#define VERIFY_OPTION(x) { if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } } +#define VERIFY_OPTION_REF(x) { if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } fRefCount = true; } + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::processAddRemCommand(const RlvCommand& rlvCmd) +{ + // NOTE: - at this point the command has already been: + // * added to the RlvObject + // * removed from the RlvObject (which still exists at this point even if this is the last restriction) + // - the object's UUID may or may not exist in gObjectList (see handling of @detach=n|y) + + // Try a command processor first + ERlvCmdRet eRet = rlvCmd.processCommand(); + if (RLV_RET_NO_PROCESSOR != eRet) + { + return eRet; + } + + // Process the command the legacy way + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); ERlvParamType eType = rlvCmd.getParamType(); + + eRet = RLV_RET_SUCCESS; bool fRefCount = false; const std::string& strOption = rlvCmd.getOption(); + switch (eBhvr) + { + case RLV_BHVR_ATTACHTHIS: // @attachthis[:<option>]=n|y + case RLV_BHVR_DETACHTHIS: // @detachthis[:<option>]=n|y + eRet = onAddRemFolderLock(rlvCmd, fRefCount); + break; + case RLV_BHVR_ATTACHTHISEXCEPT: // @attachthisexcept[:<option>]=n|y + case RLV_BHVR_DETACHTHISEXCEPT: // @detachthisexcept[:<option>]=n|y + eRet = onAddRemFolderLockException(rlvCmd, fRefCount); + break; + case RLV_BHVR_ADDOUTFIT: // @addoutfit[:<layer>]=n|y - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + case RLV_BHVR_REMOUTFIT: // @remoutfit[:<layer>]=n|y - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c + { + // If there's an option it should specify a wearable type name (reference count on no option *and* a valid option) + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + VERIFY_OPTION_REF( (rlvCmdOption.isEmpty()) || (rlvCmdOption.isWearableType()) ); + + // We need to flush any queued force-wear commands before changing the restrictions + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + ERlvLockMask eLock = (RLV_BHVR_ADDOUTFIT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; + for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) + { + if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType()) ) + { + if (RLV_TYPE_ADD == eType) + gRlvWearableLocks.addWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock); + else + gRlvWearableLocks.removeWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock); + } + } + } + break; + case RLV_BHVR_SHAREDWEAR: // @sharedwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + case RLV_BHVR_SHAREDUNWEAR: // @sharedunwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + { + VERIFY_OPTION_REF(strOption.empty()); + + RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_SHAREDPATH, LLStringUtil::null); + RlvFolderLocks::ELockScope eLockScope = RlvFolderLocks::SCOPE_SUBTREE; + ERlvLockMask eLockType = (RLV_BHVR_SHAREDUNWEAR == eBhvr) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; + + if (RLV_TYPE_ADD == eType) + RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + } + break; + case RLV_BHVR_UNSHAREDWEAR: // @unsharedwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + case RLV_BHVR_UNSHAREDUNWEAR: // @unsharedunwear=n|y - Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g + { + VERIFY_OPTION_REF(strOption.empty()); + + // Lock down the inventory root + RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_ROOTFOLDER, 0); + RlvFolderLocks::ELockScope eLockScope = RlvFolderLocks::SCOPE_SUBTREE; + ERlvLockMask eLockType = (RLV_BHVR_UNSHAREDUNWEAR == eBhvr) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; + + if (RLV_TYPE_ADD == eType) + RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_DENY, eLockScope, rlvCmd.getObjectID(), eLockType); + + // Add the #RLV shared folder as an exception + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_SHAREDPATH, LLStringUtil::null); + if (RLV_TYPE_ADD == eType) + RlvFolderLocks::instance().addFolderLock(lockSource, RlvFolderLocks::PERM_ALLOW, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, RlvFolderLocks::PERM_ALLOW, eLockScope, rlvCmd.getObjectID(), eLockType); + } + break; + case RLV_BHVR_REDIRCHAT: // @redirchat:<channel>=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h + case RLV_BHVR_REDIREMOTE: // @rediremote:<channel>=n|y - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h + { + // There should be an option which should specify a valid reply channel (if there's an empty option the command is invalid) + S32 nChannel = 0; + VERIFY_OPTION_REF( (LLStringUtil::convertToS32(strOption, nChannel)) && (RlvUtil::isValidReplyChannel(nChannel)) ); + + if (RLV_TYPE_ADD == eType) + addException(rlvCmd.getObjectID(), eBhvr, nChannel); + else + removeException(rlvCmd.getObjectID(), eBhvr, nChannel); + } + break; + case RLV_BHVR_NOTIFY: // @notify:<params>=add|rem - Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + { + // There should be an option that we can successfully parse (if there's an empty option the command is invalid) + S32 nChannel; std::string strFilter; + VERIFY_OPTION_REF( (!strOption.empty()) && (rlvParseNotifyOption(strOption, nChannel, strFilter)) ); + + if (RLV_TYPE_ADD == eType) + RlvBehaviourNotifyHandler::getInstance()->addNotify(rlvCmd.getObjectID(), nChannel, strFilter); + else + RlvBehaviourNotifyHandler::getInstance()->removeNotify(rlvCmd.getObjectID(), nChannel, strFilter); + } + break; + // + // Unknown or invalid + // + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvExtCommandHandler::onAddRemCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN; + default: + // Fail with "Invalid param" if none of the above handled it + eRet = RLV_RET_FAILED_PARAM; + break; + } + + // If this command represents a behaviour restriction that's been added/removed then we need to do some additional processing + if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) ) + { + if (RLV_TYPE_ADD == eType) + { + if (rlvCmd.isStrict()) + addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + m_Behaviours[eBhvr]++; + rlvCmd.markRefCounted(); + } + else + { + if (rlvCmd.isStrict()) + removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + m_Behaviours[eBhvr]--; + } + + m_OnBehaviour(eBhvr, eType); + if ( ((RLV_TYPE_ADD == eType) && (1 == m_Behaviours[eBhvr])) || ((RLV_TYPE_REMOVE == eType) && (0 == m_Behaviours[eBhvr])) ) + m_OnBehaviourToggle(eBhvr, eType); + } + + return eRet; +} + +// Handles reference counting of behaviours and tracks strict exceptions for @permissive (all restriction handlers should call this function) +ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(const RlvCommand& rlvCmd, RlvBhvrHandlerFunc* pHandlerFunc, RlvBhvrToggleHandlerFunc* pToggleHandlerFunc) +{ + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); + bool fRefCount = false, fHasBhvr = gRlvHandler.hasBehaviour(eBhvr); + + ERlvCmdRet eRet = (*pHandlerFunc)(rlvCmd, fRefCount); + + // If this command represents a restriction that's been added/removed then we need to do some additional processing + if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + if (rlvCmd.isStrict()) + gRlvHandler.addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + gRlvHandler.m_Behaviours[eBhvr]++; + rlvCmd.markRefCounted(); + } + else + { + if (rlvCmd.isStrict()) + gRlvHandler.removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr); + gRlvHandler.m_Behaviours[eBhvr]--; + } + + gRlvHandler.m_OnBehaviour(eBhvr, rlvCmd.getParamType()); + if (fHasBhvr != gRlvHandler.hasBehaviour(eBhvr)) + { + if (pToggleHandlerFunc) + (*pToggleHandlerFunc)(eBhvr, !fHasBhvr); + gRlvHandler.m_OnBehaviourToggle(eBhvr, rlvCmd.getParamType()); + } + } + + return eRet; +} + +// Handles: @bhvr=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be no option + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr:<uuid>=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid UUID + LLUUID idException; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idException)) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + else + gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr[:<uuid>]=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there is an option then it should specify a valid UUID (but don't reference count) + if (rlvCmd.hasOption()) + { + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_EXCEPTION>::onCommand(rlvCmd, fRefCount); + fRefCount = false; + return eRet; + } + return RlvBehaviourGenericHandler<RLV_OPTION_NONE>::onCommand(rlvCmd, fRefCount); +} + +// Handles: @bhvr:<modifier>=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks) + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + RlvBehaviourModifierValue modValue; + if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) ) + return RLV_RET_FAILED_OPTION; + + // HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + pBhvrModifier->addValue(modValue, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + } + else + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + pBhvrModifier->removeValue(modValue, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @bhvr[:<modifier>]=n|y +template<> +ERlvCmdRet RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_MODIFIER>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there is an option then it should specify a valid modifier (and reference count) + if (rlvCmd.hasOption()) + return RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount); + + // Add the default option on an empty modifier if needed + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + if ( (pBhvrModifier) && (pBhvrModifier->getAddDefault()) ) + { + // HACK-RLVa: reference counting doesn't happen until control returns to our caller but the modifier callbacks will happen now so we need to adjust the reference counts here + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + pBhvrModifier->addValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + } + else + { + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]--; + pBhvrModifier->removeValue(pBhvrModifier->getDefaultValue(), rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + gRlvHandler.m_Behaviours[rlvCmd.getBehaviourType()]++; + } + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @addattach[:<attachpt>]=n|y and @remattach[:<attachpt>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourAddRemAttachHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // Sanity check - if there's an option it should specify a valid attachment point name + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption()); + if ( (!idxAttachPt) && (!rlvCmd.getOption().empty()) ) + return RLV_RET_FAILED_OPTION; + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + // We need to flush any queued force-wear commands before changing the restrictions + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + ERlvLockMask eLock = (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD; + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock); + else + gRlvAttachmentLocks.removeAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock); + } + } + + fRefCount = rlvCmd.getOption().empty(); // Only reference count global locks + return RLV_RET_SUCCESS; +} + +// Handles: @detach[:<attachpt>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_DETACH>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // We need to flush any queued force-wear commands before changing the restrictions + if (RlvForceWear::instanceExists()) + RlvForceWear::instance().done(); + + if (rlvCmd.getOption().empty()) // @detach=n|y - RLV_LOCK_REMOVE locks an attachment *object* + { + // The object may or may not exist (it may not have rezzed yet, or it may have already been killed): + // * @detach=n: - if it has rezzed then we'll already have looked up what we need (see next line if it's not an attachment) + // - if it hasn't rezzed yet then it's a @detach=n from a non-attachment and RlvHandler::onAttach() takes care of it + // * @detach=y: - if it ever rezzed as an attachment we'll have cached the UUID of its root + // - if it never rezzed as an attachment there won't be a lock to remove + RlvHandler::rlv_object_map_t::const_iterator itObj = gRlvHandler.m_Objects.find(rlvCmd.getObjectID()); + if ( (itObj != gRlvHandler.m_Objects.end()) && (itObj->second.hasLookup()) && (itObj->second.getAttachPt()) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentLock(itObj->second.getRootID(), itObj->first); + else + gRlvAttachmentLocks.removeAttachmentLock(itObj->second.getRootID(), itObj->first); + } + } + else // @detach:<attachpt>=n|y - RLV_LOCK_ADD and RLV_LOCK_REMOVE locks an attachment *point* + { + // The attachment point index should always be non-zero for @detach:<attachpt>=n|y + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption()); + if (0 == idxAttachPt) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvAttachmentLocks.addAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE)); + else + gRlvAttachmentLocks.removeAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE)); + } + + fRefCount = false; // Don't reference count @detach[:<option>]=n + return RLV_RET_SUCCESS; +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Added: RLVa-1.3.0b +ERlvCmdRet RlvHandler::onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount) +{ + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + + RlvFolderLocks::folderlock_source_t lockSource; + if (rlvCmdOption.isEmpty()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_ATTACHMENT, rlvCmd.getObjectID()); + } + else if (rlvCmdOption.isSharedFolder()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_SHAREDPATH, rlvCmd.getOption()); + } + else if (rlvCmdOption.isAttachmentPoint()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_ATTACHMENTPOINT, RlvAttachPtLookup::getAttachPointIndex(rlvCmdOption.getAttachmentPoint())); + } + else if (rlvCmdOption.isWearableType()) + { + lockSource = RlvFolderLocks::folderlock_source_t(RlvFolderLocks::ST_WEARABLETYPE, rlvCmdOption.getWearableType()); + } + else + { + fRefCount = false; // Don't reference count failure + return RLV_RET_FAILED_OPTION; + } + + // Determine the lock type + ERlvLockMask eLockType = (RLV_BHVR_ATTACHTHIS == rlvCmd.getBehaviourType()) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; + + // Determine the folder lock options from the issued behaviour + RlvFolderLocks::ELockPermission eLockPermission = RlvFolderLocks::PERM_DENY; + RlvFolderLocks::ELockScope eLockScope = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & rlvCmd.getBehaviourFlags()) ? RlvFolderLocks::SCOPE_SUBTREE : RlvFolderLocks::SCOPE_NODE; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + RlvFolderLocks::instance().addFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +ERlvCmdRet RlvHandler::onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // Sanity check - the option should specify a shared folder path + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (!rlvCmdOption.isSharedFolder()) + return RLV_RET_FAILED_OPTION; + + ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); + + // Determine the lock type + ERlvLockMask eLockType = (RLV_BHVR_ATTACHTHISEXCEPT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE; + + // Determine the folder lock options from the issued behaviour + RlvFolderLocks::ELockPermission eLockPermission = RlvFolderLocks::PERM_ALLOW; + RlvFolderLocks::ELockScope eLockScope = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & rlvCmd.getBehaviourFlags()) ? RlvFolderLocks::SCOPE_SUBTREE : RlvFolderLocks::SCOPE_NODE; + + RlvFolderLocks::folderlock_source_t lockSource(RlvFolderLocks::ST_SHAREDPATH, rlvCmd.getOption()); + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + RlvFolderLocks::instance().addFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + else + RlvFolderLocks::instance().removeFolderLock(lockSource, eLockPermission, eLockScope, rlvCmd.getObjectID(), eLockType); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @edit=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_EDIT>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + { + // Turn off "View / Highlight Transparent" + LLDrawPoolAlpha::sShowDebugAlpha = FALSE; + + // Hide the beacons floater if it's currently visible + if (LLFloaterReg::instanceVisible("beacons")) + LLFloaterReg::hideInstance("beacons"); + + // Hide the build floater + LLToolMgr::instance().leaveBuildMode(); + } + + // Start or stop filtering opening the beacons floater + if (fHasBhvr) + RlvUIEnabler::instance().addGenericFloaterFilter("beacons"); + else + RlvUIEnabler::instance().removeGenericFloaterFilter("beacons"); +} + +// Handles: @setoverlay=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETOVERLAY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + // Once an object has exclusive control over the overlay only its behaviours should be active. This affects: + // - behaviour modifiers => handled for us once we set the primary object + + LLUUID idRlvObject; + if (fHasBhvr) + { + // Get the UUID of the primary object (there should only be one) + std::list<const RlvObject*> lObjects; + gRlvHandler.findBehaviour(RLV_BHVR_SETOVERLAY, lObjects); + RLV_ASSERT(lObjects.size() == 1); + idRlvObject = lObjects.front()->getObjectID(); + } + + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_ALPHA)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TINT)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TEXTURE)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TOUCH)->setPrimaryObject(idRlvObject); +} + +// Handles: @setoverlay_texture:<uuid>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_OVERLAY_TEXTURE>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TEXTURE)) + { + if (pBhvrModifier->hasValue()) + gRlvHandler.setOverlayImage(pBhvrModifier->getValue<LLUUID>()); + else + gRlvHandler.clearOverlayImage(); + } +} + +// Handles: @sendchannel[:<channel>]=n|y and @sendchannel_except[:<channel>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourSendChannelHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // If there's an option then it should be a valid (= positive and non-zero) chat channel + if (rlvCmd.hasOption()) + { + S32 nChannel = 0; + if ( (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nChannel)) || (nChannel <= 0) ) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), nChannel); + else + gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), nChannel); + } + else + { + fRefCount = true; + } + return RLV_RET_SUCCESS; +} + +// Handles: @recvim[:<uuid|range>]=n|y, @sendim[:<uuid|range>]=n|y and @startim[:<uuid|range>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourRecvSendStartIMHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS != eRet) && (rlvCmd.hasOption()) ) + { + // Check for <dist_min>[;<dist_max>] option + std::vector<std::string> optionList; float nDistMin = F32_MAX, nDistMax = F32_MAX; + if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (optionList.size() > 2) || + (!RlvCommandOptionHelper::parseOption(optionList[0], nDistMin)) || (nDistMin < 0) || + ( (optionList.size() >= 2) && (!RlvCommandOptionHelper::parseOption(optionList[1], nDistMax)) ) || (nDistMax < 0) ) + { + return RLV_RET_FAILED_OPTION; + } + + // Valid option(s) - figure out which modifier(s) to change + ERlvBehaviourModifier eModDistMin, eModDistMax; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_RECVIM: + eModDistMin = RLV_MODIFIER_RECVIMDISTMIN; eModDistMax = RLV_MODIFIER_RECVIMDISTMAX; + break; + case RLV_BHVR_SENDIM: + eModDistMin = RLV_MODIFIER_SENDIMDISTMIN; eModDistMax = RLV_MODIFIER_SENDIMDISTMAX; + break; + case RLV_BHVR_STARTIM: + eModDistMin = RLV_MODIFIER_STARTIMDISTMIN; eModDistMax = RLV_MODIFIER_STARTIMDISTMAX; + break; + default: + return RLV_RET_FAILED_OPTION; + } + + RlvBehaviourModifier *pBhvrModDistMin = RlvBehaviourDictionary::instance().getModifier(eModDistMin), *pBhvrModDistMax = RlvBehaviourDictionary::instance().getModifier(eModDistMax); + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + pBhvrModDistMin->addValue(nDistMin * nDistMin, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + if (optionList.size() >= 2) + pBhvrModDistMax->addValue(nDistMax * nDistMax, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + } + else + { + pBhvrModDistMin->removeValue(nDistMin * nDistMin, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + if (optionList.size() >= 2) + pBhvrModDistMax->removeValue(nDistMax * nDistMax, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + } + + fRefCount = true; + return RLV_RET_SUCCESS; + } + return eRet; +} + +// Handles: @sendim=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SENDIM>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + gSavedPerAccountSettings.getControl("DoNotDisturbModeResponse")->setHiddenFromSettingsEditor(fHasBhvr); +} + +// Handles: @setcam_avdistmin:<distance>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_AVDISTMIN>::onValueChange() const +{ + if ( (gAgentCamera.cameraMouselook()) && (!RlvActions::canChangeToMouselook()) ) + gAgentCamera.changeCameraToThirdPerson(); +} + +// Handles: @setcam_eyeoffset:<vector3>=n|y and @setcam_focusoffset:<vector3>=n|y toggles +template<> template<> +void RlvBehaviourCamEyeFocusOffsetHandler::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + { + gAgentCamera.switchCameraPreset(CAMERA_RLV_SETCAM_VIEW); + } + else + { + const RlvBehaviourModifier* pBhvrEyeModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET); + const RlvBehaviourModifier* pBhvrOffsetModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET); + if ( (!pBhvrEyeModifier->hasValue()) && (!pBhvrOffsetModifier->hasValue()) ) + gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); + } +} + +// Handles: @setcam_eyeoffset:<vector3>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET)) + { + LLControlVariable* pControl = gSavedSettings.getControl("CameraOffsetRLVaView"); + if (pBhvrModifier->hasValue()) + pControl->setValue(pBhvrModifier->getValue<LLVector3>().getValue()); + else + pControl->resetToDefault(); + } +} + +// Handles: @setcam_focusoffset:<vector3>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOCUSOFFSET>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET)) + { + LLControlVariable* pControl = gSavedSettings.getControl("FocusOffsetRLVaView"); + if (pBhvrModifier->hasValue()) + pControl->setValue(pBhvrModifier->getValue<LLVector3>().getValue()); + else + pControl->resetToDefault(); + } +} + +// Handles: @setcam_fovmin:<angle>=n|y and @setcam_fovmax:<angle>=n|y +template<> template<> +ERlvCmdRet RlvBehaviourSetCamFovHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + static float s_nLastCameraAngle = DEFAULT_FIELD_OF_VIEW; + + S32 nRefMinBhvr = gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_FOVMIN], nRefMaxBhvr = gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_FOVMAX]; + LLControlVariable* pSetting = gSavedSettings.getControl("CameraAngle"); + + // Save the user's current FOV angle if nothing's been restricted (yet) + if ( (!nRefMinBhvr) && (!nRefMaxBhvr) && (pSetting) ) + s_nLastCameraAngle = (pSetting->isPersisted()) ? LLViewerCamera::instance().getDefaultFOV() : DEFAULT_FIELD_OF_VIEW; + + // Perform default handling of the command + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_MODIFIER>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) && (pSetting) ) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + // Don't persist changes from this point + pSetting->setPersist(LLControlVariable::PERSIST_NO); + } + else if ( (RLV_TYPE_REMOVE == rlvCmd.getParamType()) && (1 == nRefMinBhvr + nRefMaxBhvr) ) + { + // Restore the user's last FOV angle (and resume persistance) + LLViewerCamera::instance().setDefaultFOV(s_nLastCameraAngle); + pSetting->setPersist(LLControlVariable::PERSIST_NONDFT); + } + } + return eRet; +} + +// Handles: @setcam_fovmin:<angle>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMIN>::onValueChange() const +{ + LLViewerCamera::instance().setDefaultFOV(LLViewerCamera::instance().getDefaultFOV()); +} + +// Handles: @setcam_fovmax:<angle>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMAX>::onValueChange() const +{ + LLViewerCamera::instance().setDefaultFOV(LLViewerCamera::instance().getDefaultFOV()); +} + +// Handles: @setcam_mouselook=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_MOUSELOOK>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if ((fHasBhvr) && (gAgentCamera.cameraMouselook())) + gAgentCamera.changeCameraToThirdPerson(); +} + +// Handles: @setcam_textures[:<uuid>=n|y changes +template<> +void RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_TEXTURE>::onValueChange() const +{ + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)) + { + if (pBhvrModifier->hasValue()) + { + RLV_INFOS << "Toggling diffuse textures for @setcam_textures" << RLV_ENDL; + LLViewerFetchedTexture::sDefaultDiffuseImagep = LLViewerTextureManager::getFetchedTexture(pBhvrModifier->getValue<LLUUID>(), FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + gObjectList.setAllObjectDefaultTextures(LLRender::DIFFUSE_MAP, true); + } + else + { + RLV_INFOS << "Restoring diffuse textures for @setcam_textures" << RLV_ENDL; + gObjectList.setAllObjectDefaultTextures(LLRender::DIFFUSE_MAP, false); + LLViewerFetchedTexture::sDefaultDiffuseImagep = nullptr; + } + } +} + +// Handles: @setcam_unlock=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_UNLOCK>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (fHasBhvr) + handle_reset_view(); +} + +// Handles: @setcam=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETCAM>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + // Once an object has exclusive control over the camera only its behaviours should be active. This affects: + // - behaviour modifiers => it's all handled for us once we set the primary object + // - RLV_BHVR_SETCAM_UNLOCK => manually (re)set the reference count (and possibly invoke the toggle handler) + + LLUUID idRlvObject; bool fHasCamUnlock = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK); + if (fHasBhvr) + { + // Get the UUID of the primary object + std::list<const RlvObject*> lObjects; + gRlvHandler.findBehaviour(RLV_BHVR_SETCAM, lObjects); + idRlvObject = lObjects.front()->getObjectID(); + // Reset the @setcam_unlock reference count + gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_UNLOCK] = (lObjects.front()->hasBehaviour(RLV_BHVR_SETCAM_UNLOCK, false)) ? 1 : 0; + } + else + { + std::list<const RlvObject*> lObjects; + // Restore the @setcam_unlock reference count + gRlvHandler.findBehaviour(RLV_BHVR_SETCAM_UNLOCK, lObjects); + gRlvHandler.m_Behaviours[RLV_BHVR_SETCAM_UNLOCK] = lObjects.size(); + } + + // Manually invoke the @setcam_unlock toggle handler if we toggled it on/off + if (fHasCamUnlock != gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_UNLOCK)) + RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_UNLOCK>::onCommandToggle(RLV_BHVR_SETCAM_UNLOCK, !fHasCamUnlock); + + gAgentCamera.switchCameraPreset( (fHasBhvr) ? CAMERA_RLV_SETCAM_VIEW : CAMERA_PRESET_REAR_VIEW ); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMIN)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_AVDISTMAX)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMIN)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_ORIGINDISTMAX)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_EYEOFFSET)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOCUSOFFSET)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOVMIN)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_FOVMAX)->setPrimaryObject(idRlvObject); + RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)->setPrimaryObject(idRlvObject); +} + +// Handles: @setdebug=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETDEBUG>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + for (const auto& dbgSetting : RlvExtGetSet::m_DbgAllowed) + { + if (dbgSetting.second & RlvExtGetSet::DBG_WRITE) + gSavedSettings.getControl(dbgSetting.first)->setHiddenFromSettingsEditor(fHasBhvr); + } +} + +// Handles: @setenv=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SETENV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + const std::string strEnvFloaters[] = { "env_post_process", "env_settings", "env_delete_preset", "env_edit_sky", "env_edit_water", "env_edit_day_cycle" }; + for (int idxFloater = 0, cntFloater = sizeof(strEnvFloaters) / sizeof(std::string); idxFloater < cntFloater; idxFloater++) + { + if (fHasBhvr) + { + // Hide the floater if it's currently visible + LLFloaterReg::const_instance_list_t envFloaters = LLFloaterReg::getFloaterList(strEnvFloaters[idxFloater]); + for (LLFloater* pFloater : envFloaters) + pFloater->closeFloater(); + RlvUIEnabler::instance().addGenericFloaterFilter(strEnvFloaters[idxFloater]); + } + else + { + RlvUIEnabler::instance().removeGenericFloaterFilter(strEnvFloaters[idxFloater]); + } + } + + // Don't allow toggling "Basic Shaders" and/or "Atmopsheric Shaders" through the debug settings under @setenv=n + gSavedSettings.getControl("VertexShaderEnable")->setHiddenFromSettingsEditor(fHasBhvr); + gSavedSettings.getControl("WindLightUseAtmosShaders")->setHiddenFromSettingsEditor(fHasBhvr); + + // Restore the user's WindLight preferences when releasing + if (!fHasBhvr) + LLEnvManagerNew::instance().usePrefs(); +} + +// Handles: @showhovertext:<uuid>=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWHOVERTEXT>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // There should be an option and it should specify a valid UUID + LLUUID idException; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idException)) + return RLV_RET_FAILED_OPTION; + + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + gRlvHandler.addException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + else + gRlvHandler.removeException(rlvCmd.getObjectID(), rlvCmd.getBehaviourType(), idException); + + // Clear/restore the object's hover text as needed + LLViewerObject* pObj = gObjectList.findObject(idException); + if ( (pObj) && (pObj->mText.notNull()) && (!pObj->mText->getObjectText().empty()) ) + pObj->mText->setString( (RLV_TYPE_ADD == rlvCmd.getParamType()) ? "" : pObj->mText->getObjectText()); + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @showinv=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWINV>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // + // When disabling, close any inventory floaters that may be open + // + if (fHasBhvr) + { + LLFloaterReg::const_instance_list_t invFloaters = LLFloaterReg::getFloaterList("inventory"); + for (LLFloater* pFloater : invFloaters) + pFloater->closeFloater(); + } + + // + // Enable/disable the "My Outfits" panel on the "My Appearance" sidebar tab + // + LLPanelOutfitsInventory* pAppearancePanel = LLPanelOutfitsInventory::findInstance(); + RLV_ASSERT(pAppearancePanel); + if (pAppearancePanel) + { + LLTabContainer* pAppearanceTabs = pAppearancePanel->getAppearanceTabs(); + LLOutfitsList* pMyOutfitsPanel = pAppearancePanel->getMyOutfitsPanel(); + if ( (pAppearanceTabs) && (pMyOutfitsPanel) ) + { + S32 idxTab = pAppearanceTabs->getIndexForPanel(pMyOutfitsPanel); + RLV_ASSERT(-1 != idxTab); + pAppearanceTabs->enableTabButton(idxTab, !fHasBhvr); + + // When disabling, switch to the COF tab if "My Outfits" is currently active + if ( (fHasBhvr) && (pAppearanceTabs->getCurrentPanelIndex() == idxTab) ) + pAppearanceTabs->selectTabPanel(pAppearancePanel->getCurrentOutfitPanel()); + } + + LLSidepanelAppearance* pCOFPanel = pAppearancePanel->getAppearanceSP(); + RLV_ASSERT(pCOFPanel); + if ( (fHasBhvr) && (pCOFPanel) && (pCOFPanel->isOutfitEditPanelVisible()) ) + { + // TODO-RLVa: we should really just be collapsing the "Add more..." inventory panel (and disable the button) + pCOFPanel->showOutfitsInventoryPanel(); + } + } + + // + // Filter (or stop filtering) opening new inventory floaters + // + if (fHasBhvr) + RlvUIEnabler::instance().addGenericFloaterFilter("inventory"); + else + RlvUIEnabler::instance().removeGenericFloaterFilter("inventory"); +} + +// Handles: @shownames[:<uuid>]=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMES>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // Update the shownames context + RlvActions::setShowName(RlvActions::SNC_DEFAULT, !fHasBhvr); + + // Refresh the nearby people list + LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people"); + RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); + if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ) + { + if (pPeoplePanel->getNearbyList()->isInVisibleChain()) + pPeoplePanel->onCommit(); + pPeoplePanel->getNearbyList()->updateAvatarNames(); + } + + // Force the use of the "display name" cache so we can filter both display and legacy names (or return back to the user's preference) + if (fHasBhvr) + { + LLAvatarNameCache::instance().setForceDisplayNames(true); + } + else + { + LLAvatarNameCache::instance().setForceDisplayNames(false); + LLAvatarNameCache::instance().setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); + } + + // Refresh all name tags and HUD text + LLVOAvatar::invalidateNameTags(); + LLHUDText::refreshAllObjectText(); +} + +// Handles: @shownames[:<uuid>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMES>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) && (!LLApp::isQuitting()) ) + { + const LLUUID idAgent = RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption()); + + // Refresh the nearby people list (if necessary) + LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people"); + RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); + if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) && (pPeoplePanel->getNearbyList()->contains(idAgent)) ) + { + if (pPeoplePanel->getNearbyList()->isInVisibleChain()) + pPeoplePanel->onCommit(); + pPeoplePanel->getNearbyList()->updateAvatarNames(); + } + + // Refresh that avatar's name tag and all HUD text + LLVOAvatar::invalidateNameTag(idAgent); + LLHUDText::refreshAllObjectText(); + } + return eRet; +} + +// Handles: @shownametags[:<uuid>]=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNAMETAGS>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // Update the shownames context + RlvActions::setShowName(RlvActions::SNC_NAMETAG, !fHasBhvr); + + // Refresh all name tags + LLVOAvatar::invalidateNameTags(); +} + +// Handles: @shownametags[:<uuid>]=n|y +template<> template<> +ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_SHOWNAMETAGS>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + ERlvCmdRet eRet = RlvBehaviourGenericHandler<RLV_OPTION_NONE_OR_EXCEPTION>::onCommand(rlvCmd, fRefCount); + if ( (RLV_RET_SUCCESS == eRet) && (rlvCmd.hasOption()) ) + LLVOAvatar::invalidateNameTag(RlvCommandOptionHelper::parseOption<LLUUID>(rlvCmd.getOption())); + return eRet; +} + +// Handles: @shownearby=n|y toggles +template<> template<> +void RlvBehaviourToggleHandler<RLV_BHVR_SHOWNEARBY>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) +{ + if (LLApp::isQuitting()) + return; // Nothing to do if the viewer is shutting down + + // Refresh the nearby people list + LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel<LLPanelPeople>("people", "panel_people"); + LLAvatarList* pNearbyList = (pPeoplePanel) ? pPeoplePanel->getNearbyList() : NULL; + RLV_ASSERT( (pPeoplePanel) && (pNearbyList) ); + if (pNearbyList) + { + static std::string s_strNoItemsMsg = pNearbyList->getNoItemsMsg(); + pNearbyList->setNoItemsMsg( (fHasBhvr) ? RlvStrings::getString("blocked_nearby") : s_strNoItemsMsg ); + pNearbyList->clear(); + + if (pNearbyList->isInVisibleChain()) + pPeoplePanel->onCommit(); + if (!fHasBhvr) + pPeoplePanel->updateNearbyList(); + } + + // Refresh that avatar's name tag and all HUD text + LLHUDText::refreshAllObjectText(); +} + +// Handles: @showself=n|y and @showselfhead=n|y toggles +template<> template<> +void RlvBehaviourShowSelfToggleHandler::onCommandToggle(ERlvBehaviour eBvhr, bool fHasBhvr) +{ + if (isAgentAvatarValid()) + gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode()); +} + +// ============================================================================ +// Command handlers (RLV_TYPE_FORCE) +// + +ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE>::processCommand(const RlvCommand& rlvCmd, RlvForceHandlerFunc* pHandler) +{ + return (*pHandler)(rlvCmd); +} + +// Handles: @bhvr:<modifier>=force +template<> +ERlvCmdRet RlvForceGenericHandler<RLV_OPTION_MODIFIER>::onCommand(const RlvCommand& rlvCmd) +{ + // The object should be holding at least one active behaviour + if (!gRlvHandler.hasBehaviour(rlvCmd.getObjectID())) + return RLV_RET_FAILED_NOBEHAVIOUR; + + // There should be an option and it should specify a valid modifier (RlvBehaviourModifier performs the appropriate type checks) + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(rlvCmd.getBehaviourType()); + RlvBehaviourModifierValue modValue; + if ( (!rlvCmd.hasOption()) || (!pBhvrModifier) || (!pBhvrModifier->convertOptionValue(rlvCmd.getOption(), modValue)) ) + return RLV_RET_FAILED_OPTION; + + pBhvrModifier->setValue(modValue, rlvCmd.getObjectID()); + return RLV_RET_SUCCESS; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0j +ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const +{ + RLV_ASSERT(RLV_TYPE_FORCE == rlvCmd.getParamType()); + + // Try a command processor first + ERlvCmdRet eRet = rlvCmd.processCommand(); + if (RLV_RET_NO_PROCESSOR != eRet) + { + return eRet; + } + + // Process the command the legacy way + eRet = RLV_RET_SUCCESS; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_UNSIT: // @unsit=force - Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g + { + VERIFY_OPTION(rlvCmd.getOption().empty()); + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (!hasBehaviourExcept(RLV_BHVR_UNSIT, rlvCmd.getObjectID())) ) + { + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + send_agent_update(TRUE, TRUE); // See behaviour notes on why we have to force an agent update here + } + } + break; + case RLV_BHVR_ADJUSTHEIGHT: // @adjustheight:<options>=force - Checked: 2015-03-30 (RLVa-1.5.0) + { + RlvCommandOptionAdjustHeight rlvCmdOption(rlvCmd); + VERIFY_OPTION(rlvCmdOption.isValid()); + if (isAgentAvatarValid()) + { + F32 nValue = (rlvCmdOption.m_nPelvisToFoot - gAgentAvatarp->getPelvisToFoot()) * rlvCmdOption.m_nPelvisToFootDeltaMult; + nValue += rlvCmdOption.m_nPelvisToFootOffset; + if (gAgentAvatarp->getRegion()->avatarHoverHeightEnabled()) + { + LLVector3 avOffset(0.0f, 0.0f, llclamp<F32>(nValue, MIN_HOVER_Z, MAX_HOVER_Z)); + gSavedPerAccountSettings.setF32("AvatarHoverOffsetZ", avOffset.mV[VZ]); + gAgentAvatarp->setHoverOffset(avOffset, true); + } + else + { + eRet = RLV_RET_FAILED_DISABLED; + } + } + } + break; + case RLV_CMD_FORCEWEAR: // @forcewear[:<options>]=force - Checked: 2011-09-12 (RLVa-1.5.0) + { + if (RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE & rlvCmd.getBehaviourFlags()) + { + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + VERIFY_OPTION(rlvCmdOption.isSharedFolder()); + eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags()); + } + else if (RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT & rlvCmd.getBehaviourFlags()) + { + RlvCommandOptionGetPath rlvGetPathOption(rlvCmd, boost::bind(&RlvHandler::onForceWearCallback, this, _1, rlvCmd.getBehaviourFlags())); + VERIFY_OPTION(rlvGetPathOption.isValid()); + eRet = (!rlvGetPathOption.isCallback()) ? RLV_RET_SUCCESS : RLV_RET_SUCCESS_DELAYED; + } + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvExtCommandHandler::onForceCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN; + default: + // Fail with "Invalid param" if none of the above handled it + eRet = RLV_RET_FAILED_PARAM; + break; + } + return eRet; +} + +// Handles: @detachme=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_DETACHME>::onCommand(const RlvCommand& rlvCmd) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + + // NOTE: @detachme should respect locks but shouldn't respect things like nostrip + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmd.getObjectID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) ) + LLVOAvatarSelf::detachAttachmentIntoInventory(pAttachObj->getAttachmentItemID()); + + return RLV_RET_SUCCESS; +} + +// Handles: @fly:[true|false]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_FLY>::onCommand(const RlvCommand& rlvCmd) +{ + bool fForceFly = true; + if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption<bool>(rlvCmd.getOption(), fForceFly)) ) + return RLV_RET_FAILED_OPTION; + + if ( (fForceFly) && (!RlvActions::canFly(rlvCmd.getObjectID())) ) + return RLV_RET_FAILED_LOCK; + + if (fForceFly != (bool)gAgent.getFlying()) + gAgent.setFlying(fForceFly); + + return RLV_RET_SUCCESS; +} + +// Handles: @remattach[:<folder|attachpt|attachgroup>]=force +template<> template<> +ERlvCmdRet RlvForceRemAttachHandler::onCommand(const RlvCommand& rlvCmd) +{ + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (rlvCmdOption.isSharedFolder()) + return gRlvHandler.onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags()); + + // @remattach:<attachpt>=force - force detach single attachment point + if (rlvCmdOption.isAttachmentPoint()) + { + RlvForceWear::instance().forceDetach(rlvCmdOption.getAttachmentPoint()); + return RLV_RET_SUCCESS; + } + // @remattach:<group>=force - force detach attachments points belonging to <group> + // @remattach=force - force detach all attachments points + else if ( (rlvCmdOption.isAttachmentPointGroup()) || (rlvCmdOption.isEmpty()) ) + { + for (const auto& entryAttachPt : gAgentAvatarp->mAttachmentPoints) + { + const LLViewerJointAttachment* pAttachPt = entryAttachPt.second; + if ( (pAttachPt) && (pAttachPt->getNumObjects()) && ((rlvCmdOption.isEmpty()) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == rlvCmdOption.getAttachmentPointGroup())) ) + { + RlvForceWear::instance().forceDetach(pAttachPt); + } + } + return RLV_RET_SUCCESS; + } + // @remattach:<uuid>=force - force detach a specific attachment + else if (rlvCmdOption.isUUID()) + { + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) ) + RlvForceWear::instance().forceDetach(pAttachObj); + return RLV_RET_SUCCESS; + } + return RLV_RET_FAILED_OPTION; +} + +// Handles: @remoutfit[:<folder|layer>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_REMOUTFIT>::onCommand(const RlvCommand& rlvCmd) +{ + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (rlvCmdOption.isSharedFolder()) + return gRlvHandler.onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourFlags()); + + if ( (!rlvCmdOption.isWearableType()) && (!rlvCmdOption.isEmpty()) ) + return RLV_RET_FAILED_OPTION; + + for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) + { + if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType())) + RlvForceWear::instance().forceRemove((LLWearableType::EType)idxType); + } + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_eyeoffset[:<vector3>]=force and @setcam_focusoffset[:<vector3>]=force +template<> template<> +ERlvCmdRet RlvForceCamEyeFocusOffsetHandler::onCommand(const RlvCommand& rlvCmd) +{ + // Enforce exclusive camera locks + if (!RlvActions::canChangeCameraPreset(rlvCmd.getObjectID())) + return RLV_RET_FAILED_LOCK; + + LLControlVariable* pOffsetControl = gSavedSettings.getControl("CameraOffsetRLVaView"); + LLControlVariable* pFocusControl = gSavedSettings.getControl("FocusOffsetRLVaView"); + LLControlVariable* pControl = (rlvCmd.getBehaviourType() == RLV_BHVR_SETCAM_EYEOFFSET) ? pOffsetControl : pFocusControl; + if (rlvCmd.hasOption()) + { + LLVector3 vecOffset; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), vecOffset)) + return RLV_RET_FAILED_OPTION; + pControl->setValue(vecOffset.getValue()); + } + else + { + pControl->resetToDefault(); + } + + gAgentCamera.switchCameraPreset( ((pOffsetControl->isDefault()) && (pFocusControl->isDefault())) ? CAMERA_PRESET_REAR_VIEW : CAMERA_RLV_SETCAM_VIEW); + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_focus:<uuid>[;<dist>[;<direction>]]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_FOCUS>::onCommand(const RlvCommand& rlvCmd) +{ + std::vector<std::string> optionList; + if (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) + return RLV_RET_FAILED_OPTION; + + LLVector3 posAgent; + LLVector3d posGlobal; + F32 camDistance; + + // Get the focus position/object (and verify it is known) + LLUUID idObject; LLVector3 posRegion; + if (RlvCommandOptionHelper::parseOption(optionList[0], idObject)) + { + const LLViewerObject* pObj = gObjectList.findObject(idObject); + if (!pObj) + return RLV_RET_FAILED_OPTION; + if (!pObj->isAvatar()) + { + posAgent = pObj->getPositionAgent(); + posGlobal = pObj->getPositionGlobal(); + } + else + { + /*const*/ LLVOAvatar* pAvatar = (/*const*/ LLVOAvatar*)pObj; + if (pAvatar->mHeadp) + { + posAgent = pAvatar->mHeadp->getWorldPosition(); + posGlobal = pAvatar->getPosGlobalFromAgent(posAgent); + } + } + camDistance = pObj->getScale().magVec(); + } + else if (RlvCommandOptionHelper::parseOption(optionList[0], posRegion)) + { + const LLViewerRegion* pRegion = gAgent.getRegion(); + if (!pRegion) + return RLV_RET_FAILED_UNKNOWN; + posAgent = pRegion->getPosAgentFromRegion(posRegion); + posGlobal = pRegion->getPosGlobalFromRegion(posRegion); + camDistance = 0.0f; + } + else + { + return RLV_RET_FAILED_OPTION; + } + + // Get the camera distance + if ( (optionList.size() > 1) && (!optionList[1].empty()) ) + { + if (!RlvCommandOptionHelper::parseOption(optionList[1], camDistance)) + return RLV_RET_FAILED_OPTION; + } + + // Get the directional vector (or calculate it from the current camera position) + LLVector3 camDirection; + if ( (optionList.size() > 2) && (!optionList[2].empty()) ) + { + if (!RlvCommandOptionHelper::parseOption(optionList[2], camDirection)) + return RLV_RET_FAILED_OPTION; + } + else + { + camDirection = LLViewerCamera::getInstance()->getOrigin() - posAgent; + } + camDirection.normVec(); + + // Move the camera in place + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); + gAgentCamera.setCameraPosAndFocusGlobal(posGlobal + LLVector3d(camDirection * llmax(F_APPROXIMATELY_ZERO, camDistance)), posGlobal, idObject); + + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_fov[:<angle>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_FOV>::onCommand(const RlvCommand& rlvCmd) +{ + if (!RlvActions::canChangeCameraFOV(rlvCmd.getObjectID())) + return RLV_RET_FAILED_LOCK; + + F32 nFOV = DEFAULT_FIELD_OF_VIEW; + if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nFOV)) ) + return RLV_RET_FAILED_OPTION; + + LLViewerCamera::getInstance()->setDefaultFOV(nFOV); + + // Don't persist non-default changes that are due to RLV; but do resume persistance once reset back to the default + if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX)) ) + { + if (LLControlVariable* pSetting = gSavedSettings.getControl("CameraAngle")) + pSetting->setPersist( (pSetting->isDefault()) ? LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO ); + } + + return RLV_RET_SUCCESS; +} + +// Handles: @setcam_mode[:<option>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETCAM_MODE>::onCommand(const RlvCommand& rlvCmd) +{ + const std::string& strOption = rlvCmd.getOption(); + if ("mouselook" == strOption) + gAgentCamera.changeCameraToMouselook(); + else if ("thirdperson" == strOption) + gAgentCamera.changeCameraToThirdPerson(); + else if ( ("reset" == strOption) || (strOption.empty()) ) + handle_reset_view(); + else + return RLV_RET_FAILED_OPTION; + return RLV_RET_SUCCESS; +} + +// Handles: @setoverlay_tween:[<alpha>];[<tint>];<duration>=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETOVERLAY_TWEEN>::onCommand(const RlvCommand& rlvCmd) +{ + std::vector<std::string> optionList; + if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (3 != optionList.size()) ) + return RLV_RET_FAILED_OPTION; + + // Parse the duration first (required param) + float tweenDuration = .0f; + if (!RlvCommandOptionHelper::parseOption(optionList[2], tweenDuration)) + return RLV_RET_FAILED_OPTION; + + // Process the overlay alpha tween (if there is one and it is a valid value) + float overlayAlpha = .0f; + if (RlvCommandOptionHelper::parseOption(optionList[0], overlayAlpha)) + RlvBehaviourModifierAnimator::instance().addTween(rlvCmd.getObjectID(), RLV_MODIFIER_OVERLAY_ALPHA, RlvBehaviourModifierAnimationType::Lerp, overlayAlpha, tweenDuration); + + // Process the overlay tint tween (if there is one and it is a valid value) + LLVector3 overlayColor; + if (RlvCommandOptionHelper::parseOption(optionList[1], overlayColor)) + RlvBehaviourModifierAnimator::instance().addTween(rlvCmd.getObjectID(), RLV_MODIFIER_OVERLAY_TINT, RlvBehaviourModifierAnimationType::Lerp, overlayColor, tweenDuration); + + return RLV_RET_SUCCESS; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const +{ + if ( (!pFolder) || (!RlvInventory::instance().isSharedFolder(pFolder->getUUID())) ) + return RLV_RET_FAILED_OPTION; + + RlvForceWear::EWearAction eAction = (RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE & nFlags) ? RlvForceWear::ACTION_REMOVE + : ((RlvBehaviourInfo::FORCEWEAR_WEAR_ADD & nFlags) ? RlvForceWear::ACTION_WEAR_ADD + : RlvForceWear::ACTION_WEAR_REPLACE); + RlvForceWear::EWearFlags eFlags = (RlvBehaviourInfo::FORCEWEAR_SUBTREE & nFlags) ? RlvForceWear::FLAG_MATCHALL : RlvForceWear::FLAG_DEFAULT; + + RlvForceWear::instance().forceFolder(pFolder, eAction, eFlags); + return RLV_RET_SUCCESS; +} + +void RlvHandler::onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const +{ + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().getPath(idItems, folders)) + { + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + onForceWear(folders.at(idxFolder), nFlags); + + // If we're not executing a command then we're a delayed callback and need to manually call done() + if ( (!getCurrentCommand()) && (RlvForceWear::instanceExists()) ) + RlvForceWear::instance().done(); + } +} + +// Handles: @setgroup:<uuid|name>[;<role>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SETGROUP>::onCommand(const RlvCommand& rlvCmd) +{ + if (!RlvActions::canChangeActiveGroup(rlvCmd.getObjectID())) + return RLV_RET_FAILED_LOCK; + + std::vector<std::string> optionList; + if ( (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) || (optionList.size() < 1) || (optionList.size() > 2) ) + return RLV_RET_FAILED_OPTION; + + LLUUID idGroup; bool fValid = false; + if ("none" == optionList[0]) + { + idGroup.setNull(); + fValid = true; + } + else if (idGroup.set(optionList[0])) + { + fValid = (idGroup.isNull()) || (gAgent.isInGroup(idGroup, true)); + } + else + { + bool fExactMatch = false; + for (const auto& groupData : gAgent.mGroups) + { + // NOTE: exact matches take precedence over partial matches; in case of partial matches the last match wins + if (boost::istarts_with(groupData.mName, optionList[0])) + { + idGroup = groupData.mID; + fExactMatch = groupData.mName.length() == optionList[0].length(); + if (fExactMatch) + break; + } + } + fValid = idGroup.notNull(); + } + + if (fValid) + { + if (!gRlvHandler.checkActiveGroupThrottle(rlvCmd.getObjectID())) + return RLV_RET_FAILED_THROTTLED; + + if (optionList.size() == 1) + gRlvHandler.setActiveGroup(idGroup); + else if (optionList.size() == 2) + gRlvHandler.setActiveGroupRole(idGroup, optionList[1]); + } + + return (fValid) ? RLV_RET_SUCCESS : RLV_RET_FAILED_OPTION; +} + +// Handles: @sit:<uuid>=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_SIT>::onCommand(const RlvCommand& rlvCmd) +{ + LLUUID idTarget; + if (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), idTarget)) + return RLV_RET_FAILED_OPTION; + + LLViewerObject* pObj = NULL; + if (idTarget.isNull()) + { + if ( (!RlvActions::canGroundSit()) || ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting())) ) + return RLV_RET_FAILED_LOCK; + gAgent.sitDown(); + send_agent_update(TRUE, TRUE); + } + else if ( ((pObj = gObjectList.findObject(idTarget)) != NULL) && (LL_PCODE_VOLUME == pObj->getPCode())) + { + if (!RlvActions::canSit(pObj)) + return RLV_RET_FAILED_LOCK; + + if ((gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid())) + { + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) ) + return RLV_RET_FAILED_LOCK; + gRlvHandler.m_posSitSource = gAgent.getPositionGlobal(); + } + + // Copy/paste from handle_sit_or_stand() + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_TargetObject); + gMessageSystem->addUUIDFast(_PREHASH_TargetID, pObj->mID); + gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3::zero); + pObj->getRegion()->sendReliableMessage(); + } + else + { + return RLV_RET_FAILED_OPTION; + } + return RLV_RET_SUCCESS; +} + +// Handles: @tpto:<vector>[;<angle>]=force and @tpto:<region>/<vector>[;<angle>]=force +template<> template<> +ERlvCmdRet RlvForceHandler<RLV_BHVR_TPTO>::onCommand(const RlvCommand& rlvCmd) +{ + std::vector<std::string> optionList; + if (!RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList)) + return RLV_RET_FAILED_OPTION; + + // We need the look-at first + LLVector3 vecLookAt = LLVector3::zero; + if (optionList.size() > 1) + { + float nAngle = 0.0f; + if (!RlvCommandOptionHelper::parseOption(optionList[1], nAngle)) + return RLV_RET_FAILED_OPTION; + + vecLookAt = LLVector3::x_axis; + vecLookAt.rotVec(nAngle, LLVector3::z_axis); + vecLookAt.normalize(); + } + + // Next figure out the destination + LLVector3d posGlobal; + if (RlvCommandOptionHelper::parseOption(optionList[0], posGlobal)) + { + if (optionList.size() == 1) + gAgent.teleportViaLocation(posGlobal); + else + gAgent.teleportViaLocationLookAt(posGlobal, vecLookAt); + } + else + { + std::vector<std::string> posList; LLVector3 posRegion; + if ( (!RlvCommandOptionHelper::parseStringList(optionList[0], posList, std::string("/"))) || (4 != posList.size()) || + (!RlvCommandOptionHelper::parseOption(optionList[0].substr(posList[0].size() + 1), posRegion)) ) + { + return RLV_RET_FAILED_OPTION; + } + + LLWorldMapMessage::url_callback_t cb = boost::bind(&RlvHandler::onTeleportCallback, &gRlvHandler, _1, posRegion, vecLookAt, rlvCmd.getObjectID()); + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(posList[0], cb, std::string(""), true); + } + + return RLV_RET_SUCCESS; +} + +// ============================================================================ +// Command handlers (RLV_TYPE_REPLY) +// + +ERlvCmdRet RlvCommandHandlerBaseImpl<RLV_TYPE_REPLY>::processCommand(const RlvCommand& rlvCmd, RlvReplyHandlerFunc* pHandler) +{ + // Sanity check - <param> should specify a - valid - reply channel + S32 nChannel; + if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) ) + return RLV_RET_FAILED_PARAM; + + std::string strReply; + ERlvCmdRet eRet = (*pHandler)(rlvCmd, strReply); + + // If we made it this far then: + // - the command was handled successfully so we send off the response + // - the command failed but we still send off an - empty - response to keep the issuing script from blocking + if (nChannel != 0) + RlvUtil::sendChatReply(nChannel, strReply); + else + { + if (RlvFloaterConsole* pConsole = LLFloaterReg::findTypedInstance<RlvFloaterConsole>("rlv_console")) + pConsole->addCommandReply(rlvCmd.getBehaviour(), strReply); + } + + return eRet; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::processReplyCommand(const RlvCommand& rlvCmd) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + + // Try a command processor first + ERlvCmdRet eRet = rlvCmd.processCommand(); + if (RLV_RET_NO_PROCESSOR != eRet) + { + return eRet; + } + + // Sanity check - <param> should specify a - valid - reply channel + S32 nChannel; + if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel, rlvCmd.getObjectID() == gAgent.getID())) ) + return RLV_RET_FAILED_PARAM; + + // Process the command the legacy way + eRet = RLV_RET_SUCCESS; std::string strReply; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_VERSION: // @version=<channel> - Checked: 2010-03-27 (RLVa-1.4.0a) + case RLV_BHVR_VERSIONNEW: // @versionnew=<channel> - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.2.0b + // NOTE: RLV will respond even if there's an option + strReply = RlvStrings::getVersion(rlvCmd.getObjectID(), RLV_BHVR_VERSION == rlvCmd.getBehaviourType()); + break; + case RLV_BHVR_VERSIONNUM: // @versionnum=<channel> - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.4b + // NOTE: RLV will respond even if there's an option + strReply = RlvStrings::getVersionNum(rlvCmd.getObjectID()); + break; + case RLV_BHVR_GETATTACH: // @getattach[:<layer>]=<channel> + eRet = onGetAttach(rlvCmd, strReply); + break; + case RLV_BHVR_GETATTACHNAMES: // @getattachnames[:<grp>]=<channel> + case RLV_BHVR_GETADDATTACHNAMES:// @getaddattachnames[:<grp>]=<channel> + case RLV_BHVR_GETREMATTACHNAMES:// @getremattachnames[:<grp>]=<channel> + eRet = onGetAttachNames(rlvCmd, strReply); + break; + case RLV_BHVR_GETOUTFIT: // @getoutfit[:<layer>]=<channel> + eRet = onGetOutfit(rlvCmd, strReply); + break; + case RLV_BHVR_GETOUTFITNAMES: // @getoutfitnames=<channel> + case RLV_BHVR_GETADDOUTFITNAMES:// @getaddoutfitnames=<channel> + case RLV_BHVR_GETREMOUTFITNAMES:// @getremoutfitnames=<channel> + eRet = onGetOutfitNames(rlvCmd, strReply); + break; + case RLV_BHVR_FINDFOLDER: // @findfolder:<criteria>=<channel> + case RLV_BHVR_FINDFOLDERS: // @findfolders:<criteria>=<channel> + eRet = onFindFolder(rlvCmd, strReply); + break; + case RLV_BHVR_GETPATH: // @getpath[:<option>]=<channel> + case RLV_BHVR_GETPATHNEW: // @getpathnew[:<option>]=<channel> + eRet = onGetPath(rlvCmd, strReply); + break; + case RLV_BHVR_GETINV: // @getinv[:<path>]=<channel> + eRet = onGetInv(rlvCmd, strReply); + break; + case RLV_BHVR_GETINVWORN: // @getinvworn[:<path>]=<channel> + eRet = onGetInvWorn(rlvCmd, strReply); + break; + case RLV_BHVR_GETGROUP: // @getgroup=<channel> - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f + strReply = (gAgent.getGroupID().notNull()) ? gAgent.getGroupName() : "none"; + break; + case RLV_BHVR_GETSITID: // @getsitid=<channel> - Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a + { + // NOTE: RLV-1.16.1 returns a NULL UUID if we're not sitting + LLUUID idSitObj; + if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) ) + { + const LLViewerObject* pSeatObj = dynamic_cast<LLViewerObject*>(gAgentAvatarp->getRoot()); + if (pSeatObj) + idSitObj = pSeatObj->getID(); + } + strReply = idSitObj.asString(); + } + break; + case RLV_BHVR_GETSTATUS: // @getstatus - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f + { + std::string strFilter, strSeparator; + if (rlvParseGetStatusOption(rlvCmd.getOption(), strFilter, strSeparator)) + { + // NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set + rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID()); + if (itObj != m_Objects.end()) + strReply = itObj->second.getStatusString(strFilter, strSeparator); + } + } + break; + case RLV_BHVR_GETSTATUSALL: // @getstatusall - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f + { + std::string strFilter, strSeparator; + if (rlvParseGetStatusOption(rlvCmd.getOption(), strFilter, strSeparator)) + { + // NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set + for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj) + strReply += itObj->second.getStatusString(strFilter, strSeparator); + } + } + break; + case RLV_BHVR_UNKNOWN: + // Pass unknown commands on to registered command handlers + return (notifyCommandHandlers(&RlvExtCommandHandler::onReplyCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN; + default: + // Fail with "Invalid param" if none of the above handled it + return RLV_RET_FAILED_PARAM; + } + + // If we made it this far then: + // - the command was handled successfully so we send off the response + // - the command failed but we still send off an - empty - response to keep the issuing script from blocking + if (nChannel > 0) + RlvUtil::sendChatReply(nChannel, strReply); + else + { + if (RlvFloaterConsole* pConsole = LLFloaterReg::findTypedInstance<RlvFloaterConsole>("rlv_console")) + pConsole->addCommandReply(rlvCmd.getBehaviour(), strReply); + } + + return eRet; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType()) || (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType()) ); + + // (Compatibility: RLV 1.16.1 returns the first random folder it finds while we return a blank on no option) + if (rlvCmd.getOption().empty()) + return RLV_RET_FAILED_OPTION; + + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().findSharedFolders(rlvCmd.getOption(), folders)) + { + if (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType()) + { + // We need to return an "in depth" result so whoever has the most '/' is our lucky winner + // (maxSlashes needs to be initialized to -1 since children of the #RLV folder won't have '/' in their shared path) + int maxSlashes = -1, curSlashes; std::string strFolderName; + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + { + strFolderName = RlvInventory::instance().getSharedPath(folders.at(idxFolder)); + + curSlashes = std::count(strFolderName.begin(), strFolderName.end(), '/'); + if (curSlashes > maxSlashes) + { + maxSlashes = curSlashes; + strReply = strFolderName; + } + } + } + else if (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType()) + { + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += RlvInventory::instance().getSharedPath(folders.at(idxFolder)); + } + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-19 (RLVa-1.4.0a) | Modified: RLVa-1.1.0e +ERlvCmdRet RlvHandler::onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT(RLV_BHVR_GETATTACH == rlvCmd.getBehaviourType()); + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + // Sanity check - <option> should specify an attachment point or be empty + S32 idxAttachPt = 0; + if ( (rlvCmd.hasOption()) && ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption())) == 0) ) + return RLV_RET_FAILED_OPTION; + + // If we're fetching all worn attachments then the reply should start with 0 + if (0 == idxAttachPt) + strReply.push_back('0'); + + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) ) + { + bool fWorn = (pAttachPt->getNumObjects() > 0) && + ( (!RlvSettings::getHideLockedAttach()) || (RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID())) ); + strReply.push_back( (fWorn) ? '1' : '0' ); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +ERlvCmdRet RlvHandler::onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_GETATTACHNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDATTACHNAMES == rlvCmd.getBehaviourType()) || + (RLV_BHVR_GETREMATTACHNAMES == rlvCmd.getBehaviourType()) ); + + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + + ERlvAttachGroupType eAttachGroup = rlvAttachGroupFromString(rlvCmd.getOption()); + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if ( (RLV_ATTACHGROUP_INVALID == eAttachGroup) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == eAttachGroup) ) + { + bool fAdd = false; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_GETATTACHNAMES: // Every attachment point that has an attached object + fAdd = (pAttachPt->getNumObjects() > 0); + break; + case RLV_BHVR_GETADDATTACHNAMES: // Every attachment point that can be attached to (wear replace OR wear add) + fAdd = (gRlvAttachmentLocks.canAttach(pAttachPt) & RLV_WEAR); + break; + case RLV_BHVR_GETREMATTACHNAMES: // Every attachment point that has at least one attachment that can be force-detached + fAdd = RlvForceWear::isForceDetachable(pAttachPt); + break; + default: + break; + } + + if (fAdd) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply.append(pAttachPt->getName()); + } + } + } + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_avdist=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_AVDIST>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + strReply = llformat("%.3lf", (gAgentCamera.getCameraPositionGlobal() - gAgent.getPositionGlobal()).magVec()); + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_avdistmin=<channel>, @getcam_avdistmax=<channel>, @getcam_fovmin=<channel> and @getcam_fovmax=<channel> +template<> template<> +ERlvCmdRet RlvReplyCamMinMaxModifierHandler::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if ( (rlvCmd.hasOption()) || (!boost::starts_with(rlvCmd.getBehaviour(), "getcam_")) ) + return RLV_RET_FAILED_OPTION; + ERlvBehaviour eBhvr = RlvBehaviourDictionary::instance().getBehaviourFromString("setcam_" + rlvCmd.getBehaviour().substr(7), RLV_TYPE_ADDREM); + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifierFromBehaviour(eBhvr)) + strReply = (pBhvrModifier->hasValue()) ? llformat("%.3f", pBhvrModifier->getValue<float>()) : LLStringUtil::null; + return RLV_RET_SUCCESS; +} + +// Handles: @camzoommin/max[:<multiplier>]=n|y - DEPRECATED +template<> template<> +ERlvCmdRet RlvBehaviourCamZoomMinMaxHandler::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) +{ + // NOTE: @camzoommin/max are implemented as semi-synonyms of @setcam_fovmin/max + F32 nMult = 1.0f; + if ( (rlvCmd.hasOption()) && (!RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), nMult)) ) + return RLV_RET_FAILED_OPTION; + + RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier( (RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_MODIFIER_SETCAM_FOVMIN : RLV_MODIFIER_SETCAM_FOVMAX); + if (pBhvrModifier) + { + if (RLV_TYPE_ADD == rlvCmd.getParamType()) + { + gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]++; + pBhvrModifier->addValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + } + else + { + gRlvHandler.m_Behaviours[(RLV_BHVR_CAMZOOMMIN == rlvCmd.getBehaviourType()) ? RLV_BHVR_SETCAM_FOVMIN : RLV_BHVR_SETCAM_FOVMAX]--; + pBhvrModifier->removeValue(DEFAULT_FIELD_OF_VIEW / nMult, rlvCmd.getObjectID(), rlvCmd.getBehaviourType()); + } + } + + fRefCount = true; + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_fov=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_FOV>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + strReply = llformat("%.3f", LLViewerCamera::getInstance()->getDefaultFOV()); + return RLV_RET_SUCCESS; +} + +// Handles: @getcam_textures=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCAM_TEXTURES>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_SETCAM_TEXTURE)) + strReply = (pBhvrModifier->hasValue()) ? pBhvrModifier->getValue<LLUUID>().asString() : LLStringUtil::null; + return RLV_RET_SUCCESS; +} + +// Handles: @getcommand[:<behaviour>[;<type>[;<separator>]]]=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETCOMMAND>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + std::vector<std::string> optionList; + RlvCommandOptionHelper::parseStringList(rlvCmd.getOption(), optionList); + + // If a second parameter is present it'll specify the command type + ERlvParamType eType = RLV_TYPE_UNKNOWN; + if (optionList.size() >= 2) + { + if ( (optionList[1] == "any") || (optionList[1].empty()) ) + eType = RLV_TYPE_UNKNOWN; + else if (optionList[1] == "add") + eType = RLV_TYPE_ADDREM; + else if (optionList[1] == "force") + eType = RLV_TYPE_FORCE; + else if (optionList[1] == "reply") + eType = RLV_TYPE_REPLY; + else + return RLV_RET_FAILED_OPTION; + } + + std::list<std::string> cmdList; + if (RlvBehaviourDictionary::instance().getCommands((optionList.size() >= 1) ? optionList[0] : LLStringUtil::null, eType, cmdList)) + strReply = boost::algorithm::join(cmdList, (optionList.size() >= 3) ? optionList[2] : std::string(RLV_OPTION_SEPARATOR) ); + return RLV_RET_SUCCESS; +} + +// Handles: @getheightoffset=<channel> +template<> template<> +ERlvCmdRet RlvReplyHandler<RLV_BHVR_GETHEIGHTOFFSET>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) +{ + if (!rlvCmd.getOption().empty()) + return RLV_RET_FAILED_OPTION; + else if (!isAgentAvatarValid()) + return RLV_RET_FAILED_UNKNOWN; + + strReply = llformat("%.2f", gAgentAvatarp->getHoverOffset()[VZ] * 100); + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT(RLV_BHVR_GETINV == rlvCmd.getBehaviourType()); + + const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption()); + if (!pFolder) + return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT; + + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); + if (!pFolders) + return RLV_RET_FAILED; + + for (S32 idxFolder = 0, cntFolder = pFolders->size(); idxFolder < cntFolder; idxFolder++) + { + // Return all folders that: + // - aren't hidden + // - aren't a folded folder (only really matters when "Enable Legacy Naming" is enabled - see related blog post) + // (we can skip checking for .<composite> folders since the ones we'll want to hide start with '.' anyway) + // - don't have any invalid characters + const std::string& strFolder = pFolders->at(idxFolder)->getName(); + if ( (!strFolder.empty()) && (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && + (!RlvInventory::isFoldedFolder(pFolders->at(idxFolder).get(), false)) && + (std::string::npos == strFolder.find_first_of(RLV_FOLDER_INVALID_CHARS)) ) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += strFolder; + } + } + return RLV_RET_SUCCESS; +} + +struct rlv_wear_info { U32 cntWorn, cntTotal, cntChildWorn, cntChildTotal; }; + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f +ERlvCmdRet RlvHandler::onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const +{ + // Sanity check - gAgentAvatarp can't be NULL [see RlvForceWear::isWearingItem()] + if (!isAgentAvatarValid()) + return RLV_RET_FAILED; + // Sanity check - folder should exist + LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption()); + if (!pFolder) + return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT; + + // Collect everything @attachall would be attaching + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvWearableItemCollector f(pFolder, RlvForceWear::ACTION_WEAR_REPLACE, RlvForceWear::FLAG_MATCHALL); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, true); + + rlv_wear_info wi = {0}; + + // Add all the folders to a lookup map + std::map<LLUUID, rlv_wear_info> mapFolders; + mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(pFolder->getUUID(), wi)); + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(folders.at(idxFolder)->getUUID(), wi)); + + // Iterate over all the found items + LLViewerInventoryItem* pItem; std::map<LLUUID, rlv_wear_info>::iterator itFolder; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + pItem = items.at(idxItem); + if (!RlvForceWear::isWearableItem(pItem)) + continue; + + // The "folded parent" is the folder this item should be considered a direct descendent of (may or may not match actual parent) + const LLUUID& idParent = f.getFoldedParent(pItem->getParentUUID()); + + // Walk up the tree: sooner or later one of the parents will be a folder in the map + LLViewerInventoryCategory* pParent = gInventory.getCategory(idParent); + while ( (itFolder = mapFolders.find(pParent->getUUID())) == mapFolders.end() ) + pParent = gInventory.getCategory(pParent->getParentUUID()); + + U32 &cntWorn = (idParent == pParent->getUUID()) ? itFolder->second.cntWorn : itFolder->second.cntChildWorn, + &cntTotal = (idParent == pParent->getUUID()) ? itFolder->second.cntTotal : itFolder->second.cntChildTotal; + + if (RlvForceWear::isWearingItem(pItem)) + cntWorn++; + cntTotal++; + } + + // Extract the result for the main folder + itFolder = mapFolders.find(pFolder->getUUID()); + wi.cntWorn = itFolder->second.cntWorn; + wi.cntTotal = itFolder->second.cntTotal; + mapFolders.erase(itFolder); + + // Build the result for each child folder + for (itFolder = mapFolders.begin(); itFolder != mapFolders.end(); ++itFolder) + { + rlv_wear_info& wiFolder = itFolder->second; + + wi.cntChildWorn += wiFolder.cntWorn + wiFolder.cntChildWorn; + wi.cntChildTotal += wiFolder.cntTotal + wiFolder.cntChildTotal; + + strReply += llformat(",%s|%d%d", gInventory.getCategory(itFolder->first)->getName().c_str(), + (0 == wiFolder.cntTotal) ? 0 : (0 == wiFolder.cntWorn) ? 1 : (wiFolder.cntWorn != wiFolder.cntTotal) ? 2 : 3, + (0 == wiFolder.cntChildTotal) ? 0 : (0 == wiFolder.cntChildWorn) ? 1 : (wiFolder.cntChildWorn != wiFolder.cntChildTotal) ? 2 : 3 + ); + } + + // Now just prepend the root and done + strReply = llformat("|%d%d", (0 == wi.cntTotal) ? 0 : (0 == wi.cntWorn) ? 1 : (wi.cntWorn != wi.cntTotal) ? 2 : 3, + (0 == wi.cntChildTotal) ? 0 : (0 == wi.cntChildWorn) ? 1 : (wi.cntChildWorn != wi.cntChildTotal) ? 2: 3) + strReply; + + return RLV_RET_SUCCESS; +} + +// Checked: 2010-03-19 (RLVa-1.4.0a) | Modified: RLVa-1.2.0a +ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT(RLV_BHVR_GETOUTFIT == rlvCmd.getBehaviourType()); + + // (Compatibility: RLV-1.16.1 will execute @getoutfit=<channel> if <layer> is invalid while we just return failure) + LLWearableType::EType wtType = LLWearableType::WT_INVALID; + if ( (rlvCmd.hasOption()) && ((wtType = LLWearableType::typeNameToType(rlvCmd.getOption())) == LLWearableType::WT_INVALID) ) + return RLV_RET_FAILED_OPTION; + + const LLWearableType::EType wtRlvTypes[] = + { + LLWearableType::WT_GLOVES, LLWearableType::WT_JACKET, LLWearableType::WT_PANTS, LLWearableType::WT_SHIRT, + LLWearableType::WT_SHOES, LLWearableType::WT_SKIRT, LLWearableType::WT_SOCKS, LLWearableType::WT_UNDERPANTS, + LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_SKIN, LLWearableType::WT_EYES, LLWearableType::WT_HAIR, + LLWearableType::WT_SHAPE, LLWearableType::WT_ALPHA, LLWearableType::WT_TATTOO, LLWearableType::WT_PHYSICS, + LLWearableType::WT_UNIVERSAL, + }; + + for (int idxType = 0, cntType = sizeof(wtRlvTypes) / sizeof(LLWearableType::EType); idxType < cntType; idxType++) + { + if ( (LLWearableType::WT_INVALID == wtType) || (wtRlvTypes[idxType] == wtType) ) + { + // We never hide body parts, even if they're "locked" and we're hiding locked layers + // (nor do we hide a layer if the issuing object is the only one that has this layer locked) + bool fWorn = (gAgentWearables.getWearableCount(wtRlvTypes[idxType]) > 0) && + ( (!RlvSettings::getHideLockedLayers()) || + (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) || + (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) ); + strReply.push_back( (fWorn) ? '1' : '0' ); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_GETOUTFITNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDOUTFITNAMES == rlvCmd.getBehaviourType()) || + (RLV_BHVR_GETREMOUTFITNAMES == rlvCmd.getBehaviourType()) ); + + // Sanity check - all these commands are optionless + if (rlvCmd.hasOption()) + return RLV_RET_FAILED_OPTION; + + for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) + { + bool fAdd = false; LLWearableType::EType wtType = (LLWearableType::EType)idxType; + switch (rlvCmd.getBehaviourType()) + { + case RLV_BHVR_GETOUTFITNAMES: // Every layer that has at least one worn wearable + fAdd = (gAgentWearables.getWearableCount(wtType) > 0); + break; + case RLV_BHVR_GETADDOUTFITNAMES: // Every layer that can be worn on (wear replace OR wear add) + fAdd = (gRlvWearableLocks.canWear(wtType) & RLV_WEAR); + break; + case RLV_BHVR_GETREMOUTFITNAMES: // Every layer that has at least one wearable that can be force-removed + fAdd = RlvForceWear::isForceRemovable(wtType); + break; + default: + break; + } + + if (fAdd) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply.append(LLWearableType::getTypeName(wtType)); + } + } + return RLV_RET_SUCCESS; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +ERlvCmdRet RlvHandler::onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const +{ + RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType()); + RLV_ASSERT( (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) ); + + RlvCommandOptionGetPath rlvGetPathOption(rlvCmd); + if (!rlvGetPathOption.isValid()) + return RLV_RET_FAILED_OPTION; + + LLInventoryModel::cat_array_t folders; + if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders)) + { + if (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType()) + { + strReply = RlvInventory::instance().getSharedPath(folders.at(0)); + } + else if (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) + { + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + { + if (!strReply.empty()) + strReply.push_back(','); + strReply += RlvInventory::instance().getSharedPath(folders.at(idxFolder)); + } + } + } + return RLV_RET_SUCCESS; +} + +// ============================================================================ +// Command specific helper functions - @setoverlay +// + +void RlvHandler::clearOverlayImage() +{ + if (m_pOverlayImage) + { + m_pOverlayImage->setBoostLevel(m_nOverlayOrigBoost); + m_pOverlayImage = nullptr; + } +} + +bool RlvHandler::hitTestOverlay(const LLCoordGL& ptMouse) const +{ + if (!m_pOverlayImage) + return false; + + RlvBehaviourModifier* pTouchModifier = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TOUCH); + return (pTouchModifier) && (pTouchModifier->hasValue()) && (pTouchModifier->getValue<bool>()) && + (m_pOverlayImage->getMask(LLVector2((float)ptMouse.mX / gViewerWindow->getWorldViewWidthScaled(), (float)ptMouse.mY / gViewerWindow->getWorldViewHeightScaled()))); +} + +void RlvHandler::renderOverlay() +{ + if ( (hasBehaviour(RLV_BHVR_SETOVERLAY)) && (m_pOverlayImage) ) + { + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } + + int nWidth = gViewerWindow->getWorldViewWidthScaled(); + int nHeight = gViewerWindow->getWorldViewHeightScaled(); + + m_pOverlayImage->addTextureStats(nWidth * nHeight); + m_pOverlayImage->setKnownDrawSize(nWidth, nHeight); + + gGL.pushMatrix(); + LLGLSUIDefault glsUI; + gViewerWindow->setup2DRender(); + + const LLVector2& displayScale = gViewerWindow->getDisplayScale(); + gGL.scalef(displayScale.mV[VX], displayScale.mV[VY], 1.f); + + gGL.getTexUnit(0)->bind(m_pOverlayImage); + const LLVector3 overlayTint = RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_TINT)->getValue<LLVector3>(); + gGL.color4f(overlayTint.mV[0], overlayTint.mV[1], overlayTint.mV[2], llclamp(RlvBehaviourDictionary::instance().getModifier(RLV_MODIFIER_OVERLAY_ALPHA)->getValue<float>(), 0.0f, 1.0f)); + + gl_rect_2d_simple_tex(nWidth, nHeight); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.popMatrix(); + gGL.flush(); + gViewerWindow->setup3DRender(); + + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } + } +} + +void RlvHandler::setOverlayImage(const LLUUID& idTexture) +{ + if ( (m_pOverlayImage) && (m_pOverlayImage->getID() == idTexture) ) + return; + + clearOverlayImage(); + m_pOverlayImage = LLViewerTextureManager::getFetchedTexture(idTexture, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + m_nOverlayOrigBoost = m_pOverlayImage->getBoostLevel(); + m_pOverlayImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + m_pOverlayImage->forceToSaveRawImage(0); +} + +// ============================================================================ diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h new file mode 100644 index 0000000000000000000000000000000000000000..85acec1bcebc757a72b30b8a5892e23bafa4f999 --- /dev/null +++ b/indra/newview/rlvhandler.h @@ -0,0 +1,311 @@ +/** + * + * Copyright (c) 2009-2018, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_HANDLER_H +#define RLV_HANDLER_H + +#include "llgroupmgr.h" +#include <stack> + +#include "rlvcommon.h" +#include "rlvhelper.h" + + // ============================================================================ + // Forward declarations + // + +class LLViewerFetchedTexture; + +// ============================================================================ + +class RlvHandler : public LLOldEvents::LLSimpleListener, public LLParticularGroupObserver +{ + // Temporary LLSingleton look-alike +public: + static RlvHandler& instance(); + static RlvHandler* getInstance(); + +public: + RlvHandler(); + ~RlvHandler(); + + // -------------------------------- + + /* + * Rule checking functions + */ + // NOTE: - to check @detach=n -> (see RlvAttachmentLocks) + // - to check @addattach=n -> (see RlvAttachmentLocks) + // - to check @remattach=n -> (see RlvAttachmentLocks) + // - to check @addoutfit=n -> (see RlvWearableLocks) + // - to check @remoutfit=n -> (see RlvWearableLocks) + // - to check exceptions -> isException() +public: + // Returns a list of all objects containing the specified behaviour + bool findBehaviour(ERlvBehaviour eBhvr, std::list<const RlvObject*>& lObjects) const; + // Returns TRUE is at least one object contains the specified behaviour (and optional option) + bool hasBehaviour(ERlvBehaviour eBhvr) const { return (eBhvr < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBhvr]) : false; } + bool hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const; + // Returns TRUE if the specified object has at least one active behaviour + bool hasBehaviour(const LLUUID& idObj) { return m_Objects.end() != m_Objects.find(idObj); } + // Returns TRUE if the specified object contains the specified behaviour (and optional option) + bool hasBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const; + // Returns TRUE if at least one object (except the specified one) contains the specified behaviour (and optional option) + bool hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const; + bool hasBehaviourExcept(ERlvBehaviour eBhvr, const std::string& strOption, const LLUUID& idObj) const; + // Returns TRUE if at least one object in the linkset with specified root ID contains the specified behaviour (and optional option) + bool hasBehaviourRoot(const LLUUID& idObjRoot, ERlvBehaviour eBhvr, const std::string& strOption = LLStringUtil::null) const; + // Returns TRUE if the specified object is the only object containing the specified behaviour + bool ownsBehaviour(const LLUUID& idObj, ERlvBehaviour eBhvr) const; + + // Adds or removes an exception for the specified behaviour + void addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption); + void removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption); + // Returns TRUE if the specified behaviour has an added exception + bool hasException(ERlvBehaviour eBhvr) const; + // Returns TRUE if the specified option was added as an exception for the specified behaviour + bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck = RLV_CHECK_DEFAULT) const; + // Returns TRUE if the specified behaviour should behave "permissive" (rather than "strict"/"secure") + bool isPermissive(ERlvBehaviour eBhvr) const; + + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // Returns TRUE if the composite folder doesn't contain any "locked" items + bool canTakeOffComposite(const LLInventoryCategory* pFolder) const; + // Returns TRUE if the composite folder doesn't replace any "locked" items + bool canWearComposite(const LLInventoryCategory* pFolder) const; + // Returns TRUE if the folder is a composite folder and optionally returns the name + bool getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const; + // Returns TRUE if the inventory item belongs to a composite folder and optionally returns the name and composite folder + bool getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const; + // Returns TRUE if the folder is a composite folder + bool isCompositeFolder(const LLInventoryCategory* pFolder) const { return getCompositeInfo(pFolder, NULL); } + // Returns TRUE if the inventory item belongs to a composite folder + bool isCompositeDescendent(const LLUUID& idItem) const { return getCompositeInfo(idItem, NULL, NULL); } + // Returns TRUE if the inventory item is part of a folded composite folder and should be hidden from @getoufit or @getattach + bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + +public: + // Adds a blocked object (= object that is blocked from issuing commands) by UUID (can be null) and/or name + void addBlockedObject(const LLUUID& idObj, const std::string& strObjName); + // Returns TRUE if there's an unresolved blocked object (known name but unknown UUID) + bool hasUnresolvedBlockedObject() const; + // Returns TRUE if the object with the specified UUID is blocked from issuing commands + bool isBlockedObject(const LLUUID& idObj) const; + // Removes a blocked object + void removeBlockedObject(const LLUUID& idObj); + + // -------------------------------- + + /* + * Helper functions + */ +public: + // Accessors/Mutators + const LLUUID& getAgentGroup() const { return m_idAgentGroup; } // @setgroup + bool getCanCancelTp() const { return m_fCanCancelTp; } // @accepttp and @tpto + void setCanCancelTp(bool fAllow) { m_fCanCancelTp = fAllow; } // @accepttp and @tpto + const LLVector3d& getSitSource() const { return m_posSitSource; } // @standtp + void setSitSource(const LLVector3d& posSource) { m_posSitSource = posSource; } // @standtp + + // Command specific helper functions + bool filterChat(std::string& strUTF8Text, bool fFilterEmote) const; // @sendchat, @recvchat and @redirchat + bool hitTestOverlay(const LLCoordGL& ptMouse) const; // @setoverlay + bool redirectChatOrEmote(const std::string& strUTF8Test) const; // @redirchat and @rediremote + void renderOverlay(); // @setoverlay + + // Command processing helper functions + ERlvCmdRet processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj); + void processRetainedCommands(ERlvBehaviour eBhvrFilter = RLV_BHVR_UNKNOWN, ERlvParamType eTypeFilter = RLV_TYPE_UNKNOWN); + bool processIMQuery(const LLUUID& idSender, const std::string& strCommand); + + // Returns a pointer to the currently executing command (do *not* save this pointer) + const RlvCommand* getCurrentCommand() const { return (!m_CurCommandStack.empty()) ? m_CurCommandStack.top() : NULL; } + // Returns the UUID of the object we're currently executing a command for + const LLUUID& getCurrentObject() const { return (!m_CurObjectStack.empty()) ? m_CurObjectStack.top() : LLUUID::null; } + + // Initialization + static bool canEnable(); + static bool isEnabled() { return m_fEnabled; } + static bool setEnabled(bool fEnable); +protected: + // Command specific helper functions (NOTE: these generally do not perform safety checks) + bool checkActiveGroupThrottle(const LLUUID& idRlvObj); // @setgroup=force + void clearOverlayImage(); // @setoverlay=n + void setActiveGroup(const LLUUID& idGroup); // @setgroup=force + void setActiveGroupRole(const LLUUID& idGroup, const std::string& strRole); // @setgroup=force + void setOverlayImage(const LLUUID& idTexture); // @setoverlay=n + + void onIMQueryListResponse(const LLSD& sdNotification, const LLSD sdResponse); + + // -------------------------------- + + /* + * Event handling + */ +public: + // The behaviour signal is triggered whenever a command is successfully processed and resulted in adding or removing a behaviour + typedef boost::signals2::signal<void (ERlvBehaviour, ERlvParamType)> rlv_behaviour_signal_t; + boost::signals2::connection setBehaviourCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviour.connect(cb); } + boost::signals2::connection setBehaviourToggleCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviourToggle.connect(cb); } + // The command signal is triggered whenever a command is processed + typedef boost::signals2::signal<void (const RlvCommand&, ERlvCmdRet, bool)> rlv_command_signal_t; + boost::signals2::connection setCommandCallback(const rlv_command_signal_t::slot_type& cb ) { return m_OnCommand.connect(cb); } + + void addCommandHandler(RlvExtCommandHandler* pHandler); + void removeCommandHandler(RlvExtCommandHandler* pHandler); +protected: + void clearCommandHandlers(); + bool notifyCommandHandlers(rlvExtCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const; + + // Externally invoked event handlers +public: + void onActiveGroupChanged(); + void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onExperienceAttach(const LLSD& sdExperience, const std::string& strObjName); + void onExperienceEvent(const LLSD& sdEvent); + bool onGC(); + void onLoginComplete(); + void onSitOrStand(bool fSitting); + void onTeleportFailed(); + void onTeleportFinished(const LLVector3d& posArrival); + static void onIdleStartup(void* pParam); +protected: + void getAttachmentResourcesCoro(const std::string& strUrl); + void onTeleportCallback(U64 hRegion, const LLVector3& posRegion, const LLVector3& vecLookAt, const LLUUID& idRlvObj); + + /* + * Base class overrides + */ +public: + // LLParticularGroupObserver implementation + void changed(const LLUUID& group_id, LLGroupChange gc) override; + // LLOldEvents::LLSimpleListener implementation + bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata) override; + + /* + * Command processing + */ +protected: + ERlvCmdRet processCommand(const RlvCommand& rlvCmd, bool fFromObj); + ERlvCmdRet processClearCommand(const RlvCommand& rlvCmd); + + // Command handlers (RLV_TYPE_ADD and RLV_TYPE_CLEAR) + ERlvCmdRet processAddRemCommand(const RlvCommand& rlvCmd); + ERlvCmdRet onAddRemFolderLock(const RlvCommand& rlvCmd, bool& fRefCount); + ERlvCmdRet onAddRemFolderLockException(const RlvCommand& rlvCmd, bool& fRefCount); + // Command handlers (RLV_TYPE_FORCE) + ERlvCmdRet processForceCommand(const RlvCommand& rlvCmd) const; + ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, U32 nFlags) const; + void onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) const; + // Command handlers (RLV_TYPE_REPLY) + ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const; + ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const; + ERlvCmdRet onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const; + + // -------------------------------- + + /* + * Member variables + */ +public: + typedef std::map<LLUUID, RlvObject> rlv_object_map_t; + typedef std::tuple<LLUUID, std::string, double> rlv_blocked_object_t; + typedef std::list<rlv_blocked_object_t> rlv_blocked_object_list_t; + typedef std::multimap<ERlvBehaviour, RlvException> rlv_exception_map_t; +protected: + rlv_object_map_t m_Objects; // Map of objects that have active restrictions (idObj -> RlvObject) + rlv_blocked_object_list_t m_BlockedObjects; // List of (attached) objects that can't issue commands + rlv_exception_map_t m_Exceptions; // Map of currently active restriction exceptions (ERlvBehaviour -> RlvException) + S16 m_Behaviours[RLV_BHVR_COUNT]; + + rlv_command_list_t m_Retained; + RlvGCTimer* m_pGCTimer; + + std::stack<const RlvCommand*> m_CurCommandStack;// Convenience (see @tpto) + std::stack<LLUUID> m_CurObjectStack; // Convenience (see @tpto) + + rlv_behaviour_signal_t m_OnBehaviour; + rlv_behaviour_signal_t m_OnBehaviourToggle; + rlv_command_signal_t m_OnCommand; + mutable std::list<RlvExtCommandHandler*> m_CommandHandlers; + boost::signals2::scoped_connection m_ExperienceEventConn; + boost::signals2::scoped_connection m_TeleportFailedConn; + boost::signals2::scoped_connection m_TeleportFinishedConn; + + static bool m_fEnabled; // Use setEnabled() to toggle this + + bool m_fCanCancelTp; // @accepttp=n and @tpto=force + mutable LLVector3d m_posSitSource; // @standtp=n (mutable because onForceXXX handles are all declared as const) + mutable LLUUID m_idAgentGroup; // @setgroup=n + std::pair<LLUUID, std::string> m_PendingGroupChange; // @setgroup=force + std::pair<LLTimer, LLUUID> m_GroupChangeExpiration; // @setgroup=force + LLPointer<LLViewerFetchedTexture> m_pOverlayImage = nullptr; // @setoverlay=n + int m_nOverlayOrigBoost = 0; // @setoverlay=n + + friend class RlvSharedRootFetcher; // Fetcher needs access to m_fFetchComplete + friend class RlvGCTimer; // Timer clear its own point at destruction + template<ERlvBehaviourOptionType> friend struct RlvBehaviourGenericHandler; + template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl; + template<ERlvParamType, ERlvBehaviour> friend struct RlvCommandHandler; + template<ERlvBehaviourModifier> friend class RlvBehaviourModifierHandler; + + // -------------------------------- + + /* + * Internal access functions + */ +public: + const rlv_object_map_t& getObjectMap() const { return m_Objects; } +}; + +typedef RlvHandler rlv_handler_t; +extern rlv_handler_t gRlvHandler; + +// ============================================================================ +// Inlined member functions +// + +inline RlvHandler& RlvHandler::instance() +{ + return gRlvHandler; +} + +inline RlvHandler* RlvHandler::getInstance() +{ + return &gRlvHandler; +} + +inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBhvr, const std::string& strOption) const +{ + return hasBehaviourExcept(eBhvr, strOption, LLUUID::null); +} + +inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBhvr, const LLUUID& idObj) const +{ + return hasBehaviourExcept(eBhvr, LLStringUtil::null, idObj); +} + +// ============================================================================ + +#endif // RLV_HANDLER_H diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a4ab3c7c0b43787a1b994b4a855b21b24efb538 --- /dev/null +++ b/indra/newview/rlvhelper.cpp @@ -0,0 +1,1889 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llappearancemgr.h" +#include "llattachmentsmgr.h" +#include "llgesturemgr.h" +#include "llnotificationsutil.h" +#include "llviewerobjectlist.h" + +#include "rlvcommon.h" +#include "rlvhelper.h" +#include "rlvhandler.h" +#include "rlvinventory.h" +#include "rlvmodifiers.h" + +#include <boost/algorithm/string.hpp> + +// ============================================================================ +// RlvBehaviourDictionary +// + +/* + * Processing of RLVa commands used to be a big switch/case loop with one function for each command type(addrem, reply + * and force). This is slowly being replaced with templated command handling which might be more confusing intially + * (also due to my poor naming schemes) but is actually far simpler and less error-prone than the old way. + * + * In the general case you just add a definition for the command below and then write the function body in rlvhandler.cpp + * and you're done! Told you this was easy. + * + * Reply command + * ============= + * Definition: RlvReplyProcessor<RLV_BHVR_COMMANDNAME>("commandname"[, <options>])); + * Implement : ERlvCmdRet RlvReplyHandler<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd, std::string& strReply) + * + * Force command + * ============= + * Definition: new RlvForceProcessor<RLV_BHVR_COMMANDNAME>("commandname"[, <options>])); + * Implement : ERlvCmdRet RlvForceProcessor<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd) + * + * Behaviours + * ========== + * Behaviours come in many forms but the added complexity is only in the variety of choices. The implementation is as + * easy as reply or force commands. + * + * For simple behaviours that only require recordkeeping and don't run code when set/unset (see ERlvBehaviourOptionType): + * Definition: RlvBehaviourGenericProcessor<RLV_OPTION_TYPE>("commandname", RLV_BHVR_COMMANDNAME) + * Implement : nothing! (it automagically works) + * For simple behaviours that only require recordkeeping and only run code when they toggle: + * Definition: RlvBehaviourGenericToggleProcessor<RLV_BHVR_COMMANDNAME, RLV_OPTION_TYPE>("commandname")) + * Implement : void RlvBehaviourToggleHandler<RLV_BHVR_COMMANDNAME>::onCommandToggle(ERlvBehaviour eBhvr, bool fHasBhvr) + * For behaviours that require manual processing: + * Definition: RlvBehaviourProcessor<RLV_BHVR_COMMANDNAME>("commandname")) + * Implement : ERlvCmdRet RlvBehaviourHandler<RLV_BHVR_COMMANDNAME>::onCommand(const RlvCommand& rlvCmd, bool& fRefCount) + * For behaviours that run code when their modifier changes: + * Definition: addModifier(RLV_BHVR_COMMANDNAME, RLV_MODIFIER_COMMANDNAME, new RlvBehaviourModifierHandler<RLV_MODIFIER_COMMANDNAME>(<default>, <auto-add>, <comparator>)); + * Implement : void RlvBehaviourModifierHandler::onValueChanged() + * + */ +RlvBehaviourDictionary::RlvBehaviourDictionary() +{ + // Array auto-initialization to 0 is still not supported in VS2013 + memset(m_BehaviourModifiers, 0, sizeof(RlvBehaviourModifier*) * RLV_MODIFIER_COUNT); + + // + // Restrictions + // + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("acceptpermission", RLV_BHVR_ACCEPTPERMISSION)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("accepttp", RLV_BHVR_ACCEPTTP, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("accepttprequest", RLV_BHVR_ACCEPTTPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_ADDATTACH, RlvBehaviourAddRemAttachHandler>("addattach")); + addEntry(new RlvBehaviourInfo("addoutfit", RLV_BHVR_ADDOUTFIT, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("allowidle", RLV_BHVR_ALLOWIDLE, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("alwaysrun", RLV_BHVR_ALWAYSRUN)); + addEntry(new RlvBehaviourInfo("attachthis", RLV_BHVR_ATTACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("attachallthis", RLV_BHVR_ATTACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourInfo("attachthis_except", RLV_BHVR_ATTACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("attachallthis_except", RLV_BHVR_ATTACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatwhisper", RLV_BHVR_CHATWHISPER)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatnormal", RLV_BHVR_CHATNORMAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("chatshout", RLV_BHVR_CHATSHOUT)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_DETACH>("detach")); + addEntry(new RlvBehaviourInfo("detachthis", RLV_BHVR_DETACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("detachallthis", RLV_BHVR_DETACHTHIS, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourInfo("detachthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_NODE)); + addEntry(new RlvBehaviourInfo("detachallthis_except", RLV_BHVR_DETACHTHISEXCEPT, RLV_TYPE_ADDREM, RlvBehaviourInfo::FORCEWEAR_SUBTREE)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_EDIT, RLV_OPTION_NONE_OR_EXCEPTION>("edit")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("editobj", RLV_BHVR_EDITOBJ)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("emote", RLV_BHVR_EMOTE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("fartouch", RLV_BHVR_FARTOUCH)); + addModifier(RLV_BHVR_FARTOUCH, RLV_MODIFIER_FARTOUCHDIST, new RlvBehaviourModifier("Fartouch Distance", RLV_MODIFIER_FARTOUCH_DEFAULT, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("fly", RLV_BHVR_FLY)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("interact", RLV_BHVR_INTERACT, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("jump", RLV_BHVR_JUMP)); + addEntry(new RlvBehaviourInfo("notify", RLV_BHVR_NOTIFY, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("permissive", RLV_BHVR_PERMISSIVE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvchat", RLV_BHVR_RECVCHAT, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvchatfrom", RLV_BHVR_RECVCHATFROM, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("recvemote", RLV_BHVR_RECVEMOTE, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvemotefrom", RLV_BHVR_RECVEMOTEFROM, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_RECVIM, RlvBehaviourRecvSendStartIMHandler>("recvim", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMIN, new RlvBehaviourModifier("RecvIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifierCompMax)); + addModifier(RLV_BHVR_RECVIM, RLV_MODIFIER_RECVIMDISTMAX, new RlvBehaviourModifier("RecvIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("recvimfrom", RLV_BHVR_RECVIMFROM, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourInfo("redirchat", RLV_BHVR_REDIRCHAT, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourInfo("rediremote", RLV_BHVR_REDIREMOTE, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_REMATTACH, RlvBehaviourAddRemAttachHandler>("remattach")); + addEntry(new RlvBehaviourInfo("remoutfit", RLV_BHVR_REMOUTFIT, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("rez", RLV_BHVR_REZ)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SENDCHANNEL, RlvBehaviourSendChannelHandler>("sendchannel", RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SENDCHANNELEXCEPT, RlvBehaviourSendChannelHandler>("sendchannel_except", RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sendchat", RLV_BHVR_SENDCHAT)); + addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SENDIM, RlvBehaviourRecvSendStartIMHandler>("sendim", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMIN, new RlvBehaviourModifier("SendIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifierCompMax)); + addModifier(RLV_BHVR_SENDIM, RLV_MODIFIER_SENDIMDISTMAX, new RlvBehaviourModifier("SendIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("sendimto", RLV_BHVR_SENDIMTO, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sendgesture", RLV_BHVR_SENDGESTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETDEBUG, RLV_OPTION_NONE>("setdebug")); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETENV, RLV_OPTION_NONE>("setenv")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("setgroup", RLV_BHVR_SETGROUP)); + addEntry(new RlvBehaviourInfo("sharedunwear", RLV_BHVR_SHAREDUNWEAR, RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("sharedwear", RLV_BHVR_SHAREDWEAR, RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SHOWHOVERTEXT>("showhovertext")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertextall", RLV_BHVR_SHOWHOVERTEXTALL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertexthud", RLV_BHVR_SHOWHOVERTEXTHUD)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showhovertextworld", RLV_BHVR_SHOWHOVERTEXTWORLD)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWINV, RLV_OPTION_NONE>("showinv")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showloc", RLV_BHVR_SHOWLOC)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showminimap", RLV_BHVR_SHOWMINIMAP)); + addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SHOWNAMES>("shownames", RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SHOWNAMETAGS>("shownametags", RlvBehaviourInfo::BHVR_STRICT )); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWNEARBY, RLV_OPTION_NONE>("shownearby", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWSELF, RLV_OPTION_NONE, RlvBehaviourShowSelfToggleHandler>("showself", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SHOWSELFHEAD, RLV_OPTION_NONE, RlvBehaviourShowSelfToggleHandler>("showselfhead", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("showworldmap", RLV_BHVR_SHOWWORLDMAP)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("sit", RLV_BHVR_SIT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("sittp", RLV_BHVR_SITTP)); + addModifier(RLV_BHVR_SITTP, RLV_MODIFIER_SITTPDIST, new RlvBehaviourModifier("SitTp Distance", RLV_MODIFIER_SITTP_DEFAULT, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("standtp", RLV_BHVR_STANDTP)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_STARTIM, RlvBehaviourRecvSendStartIMHandler>("startim", RlvBehaviourInfo::BHVR_STRICT)); + addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMIN, new RlvBehaviourModifier("StartIM Distance (Min)", F32_MAX, true, new RlvBehaviourModifierCompMax)); + addModifier(RLV_BHVR_STARTIM, RLV_MODIFIER_STARTIMDISTMAX, new RlvBehaviourModifier("StartIM Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("startimto", RLV_BHVR_STARTIMTO, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("temprun", RLV_BHVR_TEMPRUN)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchall", RLV_BHVR_TOUCHALL)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchattach", RLV_BHVR_TOUCHATTACH)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchattachother", RLV_BHVR_TOUCHATTACHOTHER)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchattachself", RLV_BHVR_TOUCHATTACHSELF)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("touchfar", RLV_BHVR_FARTOUCH, RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchhud", RLV_BHVR_TOUCHHUD, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("touchme", RLV_BHVR_TOUCHME)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_EXCEPTION>("touchthis", RLV_BHVR_TOUCHTHIS)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("touchworld", RLV_BHVR_TOUCHWORLD)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("tplm", RLV_BHVR_TPLM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("tploc", RLV_BHVR_TPLOC)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("tplocal", RLV_BHVR_TPLOCAL, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_TPLOCAL, RLV_MODIFIER_TPLOCALDIST, new RlvBehaviourModifier("Local Teleport Distance", RLV_MODIFIER_TPLOCAL_DEFAULT, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("tplure", RLV_BHVR_TPLURE, RlvBehaviourInfo::BHVR_STRICT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_EXCEPTION>("tprequest", RLV_BHVR_TPREQUEST, RlvBehaviourInfo::BHVR_STRICT | RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("unsharedunwear", RLV_BHVR_UNSHAREDUNWEAR, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourInfo("unsharedwear", RLV_BHVR_UNSHAREDWEAR, RLV_TYPE_ADDREM)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("unsit", RLV_BHVR_UNSIT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewnote", RLV_BHVR_VIEWNOTE)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewscript", RLV_BHVR_VIEWSCRIPT)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewtexture", RLV_BHVR_VIEWTEXTURE)); + + // Camera + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM, RLV_OPTION_NONE>("setcam")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdist", RLV_BHVR_SETCAM_AVDIST)); + addModifier(RLV_BHVR_SETCAM_AVDIST, RLV_MODIFIER_SETCAM_AVDIST, new RlvBehaviourModifier("Camera - Silhouette Distance", 0.0f, false, new RlvBehaviourModifierCompMax())); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_AVDISTMIN, RLV_MODIFIER_SETCAM_AVDISTMIN, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_AVDISTMIN>("Camera - Avatar Distance (Min)", 0.0f, false, new RlvBehaviourModifierCompMax())); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_AVDISTMAX, RLV_MODIFIER_SETCAM_AVDISTMAX, new RlvBehaviourModifier("Camera - Avatar Distance (Max)", F32_MAX, false, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_origindistmin", RLV_BHVR_SETCAM_ORIGINDISTMIN, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_ORIGINDISTMIN, RLV_MODIFIER_SETCAM_ORIGINDISTMIN, new RlvBehaviourModifier("Camera - Focus Distance (Min)", 0.0f, true, new RlvBehaviourModifierCompMax)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_origindistmax", RLV_BHVR_SETCAM_ORIGINDISTMAX, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_ORIGINDISTMAX, RLV_MODIFIER_SETCAM_ORIGINDISTMAX, new RlvBehaviourModifier("Camera - Focus Distance (Max)", F32_MAX, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_EYEOFFSET, RLV_MODIFIER_SETCAM_EYEOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>("Camera - Eye Offset", LLVector3::zero, true, nullptr)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_MODIFIER_SETCAM_FOCUSOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOCUSOFFSET>("Camera - Focus Offset", LLVector3::zero, true, nullptr)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SETCAM_FOVMIN, RlvBehaviourSetCamFovHandler>("setcam_fovmin")); + addModifier(RLV_BHVR_SETCAM_FOVMIN, RLV_MODIFIER_SETCAM_FOVMIN, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMIN>("Camera - FOV (Min)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifierCompMax)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_SETCAM_FOVMAX, RlvBehaviourSetCamFovHandler>("setcam_fovmax")); + addModifier(RLV_BHVR_SETCAM_FOVMAX, RLV_MODIFIER_SETCAM_FOVMAX, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_FOVMAX>("Camera - FOV (Max)", DEFAULT_FIELD_OF_VIEW, true, new RlvBehaviourModifierCompMin)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_MOUSELOOK, RLV_OPTION_NONE>("setcam_mouselook")); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("setcam_textures", RLV_BHVR_SETCAM_TEXTURES)); + addModifier(RLV_BHVR_SETCAM_TEXTURES, RLV_MODIFIER_SETCAM_TEXTURE, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_TEXTURE>("Camera - Forced Texture", IMG_DEFAULT, true, nullptr)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("setcam_unlock")); + // Camera (compatibility shim - to be deprecated) + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camavdist", RLV_BHVR_SETCAM_AVDIST, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camdistmin", RLV_BHVR_SETCAM_AVDISTMIN, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("camdistmax", RLV_BHVR_SETCAM_AVDISTMAX, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("camtextures", RLV_BHVR_SETCAM_TEXTURES, RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_CAMZOOMMIN, RlvBehaviourCamZoomMinMaxHandler>("camzoommin", RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourProcessor<RLV_BHVR_CAMZOOMMAX, RlvBehaviourCamZoomMinMaxHandler>("camzoommax", RlvBehaviourInfo::BHVR_DEPRECATED)); + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETCAM_UNLOCK, RLV_OPTION_NONE>("camunlock", RlvBehaviourInfo::BHVR_SYNONYM | RlvBehaviourInfo::BHVR_DEPRECATED)); + + // Overlay + addEntry(new RlvBehaviourGenericToggleProcessor<RLV_BHVR_SETOVERLAY, RLV_OPTION_NONE>("setoverlay", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addModifier(new RlvForceGenericProcessor<RLV_OPTION_MODIFIER>("setoverlay_alpha", RLV_BHVR_SETOVERLAY_ALPHA, RlvBehaviourInfo::BHVR_EXPERIMENTAL), + RLV_MODIFIER_OVERLAY_ALPHA, new RlvBehaviourModifier("Overlay - Alpha", 1.0f, false, new RlvBehaviourModifierComp())); + addModifier(new RlvForceGenericProcessor<RLV_OPTION_MODIFIER>("setoverlay_texture", RLV_BHVR_SETOVERLAY_TEXTURE, RlvBehaviourInfo::BHVR_EXPERIMENTAL), + RLV_MODIFIER_OVERLAY_TEXTURE, new RlvBehaviourModifierHandler<RLV_MODIFIER_OVERLAY_TEXTURE>("Overlay - Texture", LLUUID::null, false, new RlvBehaviourModifierComp())); + addModifier(new RlvForceGenericProcessor<RLV_OPTION_MODIFIER>("setoverlay_tint", RLV_BHVR_SETOVERLAY_TINT, RlvBehaviourInfo::BHVR_EXPERIMENTAL), + RLV_MODIFIER_OVERLAY_TINT, new RlvBehaviourModifier("Overlay - Tint", LLVector3(1.0f, 1.0f, 1.0f), false, new RlvBehaviourModifierComp())); + addModifier(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE_OR_MODIFIER>("setoverlay_touch", RLV_BHVR_SETOVERLAY_TOUCH, RlvBehaviourInfo::BHVR_EXPERIMENTAL), + RLV_MODIFIER_OVERLAY_TOUCH, new RlvBehaviourModifier("Overlay - Touch", true, true, new RlvBehaviourModifierComp())); + addEntry(new RlvForceProcessor<RLV_BHVR_SETOVERLAY_TWEEN>("setoverlay_tween", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + + // + // Force-wear + // + addEntry(new RlvBehaviourInfo("attach", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachallover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("attachthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("attachallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("attachthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("attachallthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvForceProcessor<RLV_BHVR_DETACH, RlvForceRemAttachHandler>("detach", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("detachall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvBehaviourInfo("detachthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvBehaviourInfo("detachallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT)); + addEntry(new RlvForceProcessor<RLV_BHVR_REMATTACH, RlvForceRemAttachHandler>("remattach", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + addEntry(new RlvForceProcessor<RLV_BHVR_REMOUTFIT>("remoutfit", RlvBehaviourInfo::FORCEWEAR_WEAR_REMOVE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE)); + // Synonyms (addoutfit* -> attach*) + addEntry(new RlvBehaviourInfo("addoutfit", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitall", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitallover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitallthis", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("addoutfitallthisover", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_ADD | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + // Synonyms (attach*overorreplace -> attach*) + addEntry(new RlvBehaviourInfo("attachoverorreplace", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("attachalloverorreplace", RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_NONE | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("attachthisoverorreplace",RLV_CMD_FORCEWEAR, RLV_TYPE_FORCE, RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_NODE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + addEntry(new RlvBehaviourInfo("attachallthisoverorreplace",RLV_CMD_FORCEWEAR,RLV_TYPE_FORCE,RlvBehaviourInfo::FORCEWEAR_WEAR_REPLACE | RlvBehaviourInfo::FORCEWEAR_SUBTREE | RlvBehaviourInfo::FORCEWEAR_CONTEXT_OBJECT | RlvBehaviourInfo::BHVR_SYNONYM)); + + // + // Force-only + // + addEntry(new RlvBehaviourInfo("adjustheight", RLV_BHVR_ADJUSTHEIGHT, RLV_TYPE_FORCE)); + addEntry(new RlvForceProcessor<RLV_BHVR_DETACHME>("detachme")); + addEntry(new RlvForceProcessor<RLV_BHVR_FLY>("fly")); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUS>("setcam_focus", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RlvForceCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_FOV>("setcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETCAM_MODE>("setcam_mode", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvForceProcessor<RLV_BHVR_SETGROUP>("setgroup")); + addEntry(new RlvForceProcessor<RLV_BHVR_SIT>("sit")); + addEntry(new RlvForceProcessor<RLV_BHVR_TPTO>("tpto")); + addEntry(new RlvBehaviourInfo("unsit", RLV_BHVR_UNSIT, RLV_TYPE_FORCE)); + + // + // Reply-only + // + addEntry(new RlvBehaviourInfo("findfolder", RLV_BHVR_FINDFOLDER, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("findfolders", RLV_BHVR_FINDFOLDERS, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("getaddattachnames", RLV_BHVR_GETADDATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getaddoutfitnames", RLV_BHVR_GETADDOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getattach", RLV_BHVR_GETATTACH, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getattachnames", RLV_BHVR_GETATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDIST>("getcam_avdist", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDISTMIN, RlvReplyCamMinMaxModifierHandler>("getcam_avdistmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_AVDISTMAX, RlvReplyCamMinMaxModifierHandler>("getcam_avdistmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOV>("getcam_fov", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOVMIN, RlvReplyCamMinMaxModifierHandler>("getcam_fovmin", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_FOVMAX, RlvReplyCamMinMaxModifierHandler>("getcam_fovmax", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCAM_TEXTURES>("getcam_textures", RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETCOMMAND>("getcommand", RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("getgroup", RLV_BHVR_GETGROUP, RLV_TYPE_REPLY)); + addEntry(new RlvReplyProcessor<RLV_BHVR_GETHEIGHTOFFSET>("getheightoffset", RlvBehaviourInfo::BHVR_EXTENDED)); + addEntry(new RlvBehaviourInfo("getinv", RLV_BHVR_GETINV, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getinvworn", RLV_BHVR_GETINVWORN, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getoutfit", RLV_BHVR_GETOUTFIT, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getoutfitnames", RLV_BHVR_GETOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getpath", RLV_BHVR_GETPATH, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getpathnew", RLV_BHVR_GETPATHNEW, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getremattachnames", RLV_BHVR_GETREMATTACHNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getremoutfitnames", RLV_BHVR_GETREMOUTFITNAMES, RLV_TYPE_REPLY, RlvBehaviourInfo::BHVR_EXPERIMENTAL)); + addEntry(new RlvBehaviourInfo("getsitid", RLV_BHVR_GETSITID, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getstatus", RLV_BHVR_GETSTATUS, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("getstatusall", RLV_BHVR_GETSTATUSALL, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("version", RLV_BHVR_VERSION, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("versionnew", RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY)); + addEntry(new RlvBehaviourInfo("versionnum", RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY)); + + // Populate m_String2InfoMap (the tuple <behaviour, type> should be unique) + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + { + RLV_VERIFY(m_String2InfoMap.insert(std::make_pair(std::make_pair(pBhvrInfo->getBehaviour(), (ERlvParamType)pBhvrInfo->getParamTypeMask()), pBhvrInfo)).second == true); + } + + // Populate m_Bhvr2InfoMap (there can be multiple entries per ERlvBehaviour) + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + { + if ( (pBhvrInfo->getParamTypeMask() & RLV_TYPE_ADDREM) && (!pBhvrInfo->isSynonym()) ) + { +#ifdef RLV_DEBUG + for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(pBhvrInfo->getBehaviourType()), m_Bhvr2InfoMap.upper_bound(pBhvrInfo->getBehaviourType()))) + { + RLV_ASSERT( (itBhvr.first != pBhvrInfo->getBehaviourType()) || (itBhvr.second->getBehaviourFlags() != pBhvrInfo->getBehaviourFlags()) ); + } +#endif // RLV_DEBUG + m_Bhvr2InfoMap.insert(std::pair<ERlvBehaviour, const RlvBehaviourInfo*>(pBhvrInfo->getBehaviourType(), pBhvrInfo)); + } + } + + // Process blocked commands + if (RlvSettings::getNoSetEnv()) + toggleBehaviourFlag("setenv", RLV_TYPE_ADDREM, RlvBehaviourInfo::BHVR_BLOCKED, true); +} + +RlvBehaviourDictionary::~RlvBehaviourDictionary() +{ + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + delete pBhvrInfo; + m_BhvrInfoList.clear(); + + for (int idxBhvrMod = 0; idxBhvrMod < RLV_MODIFIER_COUNT; idxBhvrMod++) + { + delete m_BehaviourModifiers[idxBhvrMod]; + m_BehaviourModifiers[idxBhvrMod] = nullptr; + } +} + +void RlvBehaviourDictionary::addEntry(const RlvBehaviourInfo* pEntry) +{ + // Filter experimental commands (if disabled) + static LLCachedControl<bool> sEnableExperimental(gSavedSettings, "RLVaExperimentalCommands"); + if ( (!pEntry) || ((!sEnableExperimental) && (pEntry->isExperimental())) ) + { + return; + } + + // Sanity check for duplicate entries +#ifndef LL_RELEASE_FOR_DOWNLOAD + std::for_each(m_BhvrInfoList.begin(), m_BhvrInfoList.end(), + [&pEntry](const RlvBehaviourInfo* pBhvrInfo) { + RLV_ASSERT_DBG( ((pBhvrInfo->getBehaviour()) != (pEntry->getBehaviour())) || ((pBhvrInfo->getParamTypeMask() & pEntry->getParamTypeMask()) == 0) ); + }); +#endif // LL_RELEASE_FOR_DOWNLOAD + + m_BhvrInfoList.push_back(pEntry); +} + +void RlvBehaviourDictionary::addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry) +{ + if (eModifier < RLV_MODIFIER_COUNT) + { + m_BehaviourModifiers[eModifier] = pModifierEntry; + m_Bhvr2ModifierMap.insert(std::make_pair(eBhvr, eModifier)); + } +} + +// Convenience function to add both the behaviour entry as well as the corresponding modifier entry +void RlvBehaviourDictionary::addModifier(const RlvBehaviourInfo* pBhvrEntry, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry) +{ + addEntry(pBhvrEntry); + addModifier(pBhvrEntry->getBehaviourType(), eModifier, pModifierEntry); +} + +// TODO: this shouldn't be in this class - find a better spot for it +void RlvBehaviourDictionary::clearModifiers(const LLUUID& idRlvObj) +{ + for (int idxModifier = 0; idxModifier < RLV_MODIFIER_COUNT; idxModifier++) + { + if (m_BehaviourModifiers[idxModifier]) + m_BehaviourModifiers[idxModifier]->clearValues(idRlvObj); + } +} + +const RlvBehaviourInfo* RlvBehaviourDictionary::getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const +{ + bool fStrict = boost::algorithm::ends_with(strBhvr, "_sec"); + if (pfStrict) + *pfStrict = fStrict; + + rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair( (!fStrict) ? strBhvr : strBhvr.substr(0, strBhvr.size() - 4), (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType)); + return ( (itBhvr != m_String2InfoMap.end()) && ((!fStrict) || (itBhvr->second->hasStrict())) ) ? itBhvr->second : NULL; +} + +ERlvBehaviour RlvBehaviourDictionary::getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict) const +{ + const RlvBehaviourInfo* pBhvrInfo = getBehaviourInfo(strBhvr, eParamType, pfStrict); + return (pBhvrInfo) ? pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; +} + +bool RlvBehaviourDictionary::getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const +{ + cmdList.clear(); + for (const RlvBehaviourInfo* pBhvrInfo : m_BhvrInfoList) + { + if ( (pBhvrInfo->getParamTypeMask() & eParamType) || (RLV_TYPE_UNKNOWN == eParamType) ) + { + std::string strCmd = pBhvrInfo->getBehaviour(); + if ( (std::string::npos != strCmd.find(strMatch)) || (strMatch.empty()) ) + cmdList.push_back(strCmd); + if ( (pBhvrInfo->hasStrict()) && ((std::string::npos != strCmd.append("_sec").find(strMatch)) || (strMatch.empty())) ) + cmdList.push_back(strCmd); + } + } + return !cmdList.empty(); +} + +bool RlvBehaviourDictionary::getHasStrict(ERlvBehaviour eBhvr) const +{ + for (const rlv_bhvr2info_map_t::value_type& itBhvr : boost::make_iterator_range(m_Bhvr2InfoMap.lower_bound(eBhvr), m_Bhvr2InfoMap.upper_bound(eBhvr))) + { + // Only restrictions can be strict + if (RLV_TYPE_ADDREM != itBhvr.second->getParamTypeMask()) + continue; + return itBhvr.second->hasStrict(); + } + RLV_ASSERT(false); + return false; +} + +RlvBehaviourModifier* RlvBehaviourDictionary::getModifierFromBehaviour(ERlvBehaviour eBhvr) const +{ + rlv_bhvr2mod_map_t::const_iterator itMod = m_Bhvr2ModifierMap.find(eBhvr); + ERlvBehaviourModifier eBhvrMod = (m_Bhvr2ModifierMap.end() != itMod) ? itMod->second : RLV_MODIFIER_UNKNOWN; + return (eBhvrMod < RLV_MODIFIER_UNKNOWN) ? m_BehaviourModifiers[eBhvrMod] : nullptr; +} + +void RlvBehaviourDictionary::toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBhvrFlag, bool fEnable) +{ + rlv_string2info_map_t::const_iterator itBhvr = m_String2InfoMap.find(std::make_pair(strBhvr, (eParamType & RLV_TYPE_ADDREM) ? RLV_TYPE_ADDREM : eParamType)); + if (m_String2InfoMap.end() != itBhvr) + { + const_cast<RlvBehaviourInfo*>(itBhvr->second)->toggleBehaviourFlag(eBhvrFlag, fEnable); + } +} + +// ============================================================================ +// RlvBehaviourModifier +// + +RlvBehaviourModifier::RlvBehaviourModifier(std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifierComp* pValueComparator) + : m_strName(strName), m_DefaultValue(defaultValue), m_fAddDefaultOnEmpty(fAddDefaultOnEmpty), m_pValueComparator(pValueComparator) +{ + m_pValueComparator = (pValueComparator) ? pValueComparator : new RlvBehaviourModifierComp(); +} + +RlvBehaviourModifier::~RlvBehaviourModifier() +{ + if (m_pValueComparator) + { + delete m_pValueComparator; + m_pValueComparator = NULL; + } +} + +bool RlvBehaviourModifier::addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr) +{ + if (modValue.which() == m_DefaultValue.which()) + { + m_Values.insert((m_pValueComparator) ? std::lower_bound(m_Values.begin(), m_Values.end(), std::make_tuple(modValue, idRlvObj, eBhvr), boost::bind(&RlvBehaviourModifierComp::operator(), m_pValueComparator, _1, _2)) : m_Values.end(), std::make_tuple(modValue, idRlvObj, eBhvr)); + // NOTE: change signal needs to trigger before modifier handlers so cached values have a chance to update properly + m_ChangeSignal(getValue()); + onValueChange(); + return true; + } + return false; +} + +void RlvBehaviourModifier::clearValues(const LLUUID& idRlvObj) +{ + size_t origCount = m_Values.size(); + m_Values.erase(std::remove_if(m_Values.begin(), m_Values.end(), + [&idRlvObj](const RlvBehaviourModifierValueTuple& modValue) { + return (std::get<1>(modValue) == idRlvObj) && (std::get<2>(modValue) == RLV_BHVR_UNKNOWN); + }), m_Values.end()); + RlvBehaviourModifierAnimator::instance().clearTweens(idRlvObj); + if (origCount != m_Values.size()) + { + onValueChange(); + m_ChangeSignal(getValue()); + } +} + +const LLUUID& RlvBehaviourModifier::getPrimaryObject() const +{ + return (m_pValueComparator) ? m_pValueComparator->m_idPrimaryObject : LLUUID::null; +} + +bool RlvBehaviourModifier::hasValue() const { + // If no primary object is set this returns "any value set"; otherwise it returns "any value set by the primary object" + if ( (!m_pValueComparator) || (m_pValueComparator->m_idPrimaryObject.isNull()) ) + return !m_Values.empty(); + return (!m_Values.empty()) ? std::get<1>(m_Values.front()) == m_pValueComparator->m_idPrimaryObject : false; +} + +bool RlvBehaviourModifier::hasValue(const LLUUID& idRlvObj) const +{ + return m_Values.end() != std::find_if(m_Values.begin(), m_Values.end(), [&idRlvObj](const RlvBehaviourModifierValueTuple& cmpValue) { return std::get<1>(cmpValue) == idRlvObj; }); +} + +void RlvBehaviourModifier::removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr) +{ + if ( (modValue.which() == m_DefaultValue.which()) ) + { + auto itValue = std::find(m_Values.begin(), m_Values.end(), std::make_tuple(modValue, idRlvObj, eBhvr)); + if (m_Values.end() != itValue) + { + m_Values.erase(itValue); + onValueChange(); + m_ChangeSignal(getValue()); + } + } +} + +void RlvBehaviourModifier::setPrimaryObject(const LLUUID& idPrimaryObject) +{ + if (m_pValueComparator) + { + m_pValueComparator->m_idPrimaryObject = idPrimaryObject; + m_Values.sort(boost::bind(&RlvBehaviourModifierComp::operator(), m_pValueComparator, _1, _2)); + onValueChange(); + m_ChangeSignal(getValue()); + } +} + +void RlvBehaviourModifier::setValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj) +{ + if ( (modValue.which() == m_DefaultValue.which()) ) + { + auto itValue = std::find_if(m_Values.begin(), m_Values.end(), + [&idRlvObj](const RlvBehaviourModifierValueTuple& cmpValue) { + return (std::get<1>(cmpValue) == idRlvObj) && (std::get<2>(cmpValue) == RLV_BHVR_UNKNOWN); + }); + if (m_Values.end() != itValue) + { + // The object already has a modifier value set => change it + std::get<0>(*itValue) = modValue; + if (m_pValueComparator) + m_Values.sort(boost::bind(&RlvBehaviourModifierComp::operator(), m_pValueComparator, _1, _2)); + onValueChange(); + m_ChangeSignal(getValue()); + } + else + { + // The command doesn't have a modifier value yet => add it + addValue(modValue, idRlvObj, RLV_BHVR_UNKNOWN); + } + } +} + +bool RlvBehaviourModifier::convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const +{ + try + { + if (typeid(float) == m_DefaultValue.type()) + { + modValue = std::stof(optionValue); + return true; + } + else if (typeid(int) == m_DefaultValue.type()) + { + modValue = std::stoi(optionValue); + return true; + } + else if (typeid(LLVector3) == m_DefaultValue.type()) + { + LLVector3 vecOption; + if (3 == sscanf(optionValue.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2)) + { + modValue = vecOption; + return true; + } + } + else if (typeid(LLUUID) == m_DefaultValue.type()) + { + LLUUID idOption; + if (LLUUID::parseUUID(optionValue, &idOption)) + { + modValue = idOption; + return true; + } + } + return false; + } + catch (const std::invalid_argument&) + { + return false; + } +} + +// ============================================================================ +// RlvCommmand +// + +RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand) + : m_fValid(false), m_idObj(idObj), m_pBhvrInfo(NULL), m_eParamType(RLV_TYPE_UNKNOWN), m_fStrict(false), m_fRefCounted(false) +{ + if (m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam)) + { + S32 nTemp = 0; + if ( ("n" == m_strParam) || ("add" == m_strParam) ) + m_eParamType = RLV_TYPE_ADD; + else if ( ("y" == m_strParam) || ("rem" == m_strParam) ) + m_eParamType = RLV_TYPE_REMOVE; + else if (m_strBehaviour == "clear") // clear is the odd one out so just make it its own type + m_eParamType = RLV_TYPE_CLEAR; + else if ("force" == m_strParam) + m_eParamType = RLV_TYPE_FORCE; + else if (LLStringUtil::convertToS32(m_strParam, nTemp)) // Assume it's a reply command if we can convert <param> to an S32 + m_eParamType = RLV_TYPE_REPLY; + else + { + m_eParamType = RLV_TYPE_UNKNOWN; + m_fValid = false; + } + } + + if (!m_fValid) + { + m_strOption = m_strParam = ""; + return; + } + + m_pBhvrInfo = RlvBehaviourDictionary::instance().getBehaviourInfo(m_strBehaviour, m_eParamType, &m_fStrict); +} + +RlvCommand::RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType) + : m_fValid(rlvCmd.m_fValid), m_idObj(rlvCmd.m_idObj), m_strBehaviour(rlvCmd.m_strBehaviour), m_pBhvrInfo(rlvCmd.m_pBhvrInfo), + m_eParamType( (RLV_TYPE_UNKNOWN == eParamType) ? rlvCmd.m_eParamType : eParamType),m_fStrict(rlvCmd.m_fStrict), m_strOption(rlvCmd.m_strOption), m_strParam(rlvCmd.m_strParam), m_fRefCounted(false) +{ +} + +bool RlvCommand::parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam) +{ + // (See behaviour notes for the command parsing truth table) + + // Format: <behaviour>[:<option>]=<param> + int idxParam = strCommand.find('='); + int idxOption = (idxParam > 0) ? strCommand.find(':') : -1; + if (idxOption > idxParam - 1) + idxOption = -1; + + // If <behaviour> is missing it's always an improperly formatted command + if ( (0 == idxOption) || (0 == idxParam) ) + return false; + + strBehaviour = strCommand.substr(0, (-1 != idxOption) ? idxOption : idxParam); + strOption = strParam = ""; + + // If <param> is missing it's an improperly formatted command + if ( (-1 == idxParam) || ((int)strCommand.length() - 1 == idxParam) ) + { + // Unless "<behaviour> == "clear" AND (idxOption == 0)" + // OR <behaviour> == "clear" AND (idxParam != 0) [see table above] + if ( ("clear" == strBehaviour) && ( (!idxOption) || (idxParam) ) ) + return true; + return false; + } + + if ( (-1 != idxOption) && (idxOption + 1 != idxParam) ) + strOption = strCommand.substr(idxOption + 1, idxParam - idxOption - 1); + strParam = strCommand.substr(idxParam + 1); + + return true; +} + +// ============================================================================ +// Command option parsing utility classes +// + +template<> +bool RlvCommandOptionHelper::parseOption<LLUUID>(const std::string& strOption, LLUUID& idOption) +{ + return idOption.set(strOption, false); +} + +template<> +bool RlvCommandOptionHelper::parseOption<int>(const std::string& strOption, int& nOption) +{ + try + { + nOption = std::stoi(strOption); + } + catch (const std::invalid_argument&) + { + return false; + } + return true; +} + +template<> +bool RlvCommandOptionHelper::parseOption<bool>(const std::string& strOption, bool& fOption) +{ + try + { + // Try and parse it as a number first + int nOption = std::stoi(strOption); + fOption = (bool)nOption; + return (nOption == 0) || (nOption == 1); + } + catch (const std::invalid_argument&) + { + // Then try and parse it as true/false + std::istringstream ss(strOption); + ss >> std::boolalpha >> fOption; + return !ss.fail(); + } +} + +template<> +bool RlvCommandOptionHelper::parseOption<float>(const std::string& strOption, float& nOption) +{ + try + { + nOption = std::stof(strOption); + } + catch (const std::invalid_argument&) + { + return false; + } + return true; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLWearableType::EType>(const std::string& strOption, LLWearableType::EType& wtOption) +{ + wtOption = LLWearableType::typeNameToType(strOption); + return (LLWearableType::WT_INVALID != wtOption) && (LLWearableType::WT_NONE != wtOption); +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLViewerJointAttachment*>(const std::string& strOption, LLViewerJointAttachment*& pAttachPt) +{ + pAttachPt = RlvAttachPtLookup::getAttachPoint(strOption); + return pAttachPt != NULL; +} + +template<> +bool RlvCommandOptionHelper::parseOption<ERlvAttachGroupType>(const std::string& strOption, ERlvAttachGroupType& eAttachGroup) +{ + eAttachGroup = rlvAttachGroupFromString(strOption); + return eAttachGroup != RLV_ATTACHGROUP_INVALID; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLViewerInventoryCategory*>(const std::string& strOption, LLViewerInventoryCategory*& pFolder) +{ + pFolder = RlvInventory::instance().getSharedFolder(strOption); + return pFolder != NULL; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLVector3>(const std::string& strOption, LLVector3& vecOption) + { + if (!strOption.empty()) + { + S32 cntToken = sscanf(strOption.c_str(), "%f/%f/%f", vecOption.mV + 0, vecOption.mV + 1, vecOption.mV + 2); + return (3 == cntToken); + } + return false; +} + +template<> +bool RlvCommandOptionHelper::parseOption<LLVector3d>(const std::string& strOption, LLVector3d& vecOption) + { + if (!strOption.empty()) + { + S32 cntToken = sscanf(strOption.c_str(), "%lf/%lf/%lf", vecOption.mdV + 0, vecOption.mdV + 1, vecOption.mdV + 2); + return (3 == cntToken); + } + return false; +} + +template<> +bool RlvCommandOptionHelper::parseOption<RlvCommandOptionGeneric>(const std::string& strOption, RlvCommandOptionGeneric& genericOption) +{ + LLWearableType::EType wtType(LLWearableType::WT_INVALID); LLUUID idOption; ERlvAttachGroupType eAttachGroup(RLV_ATTACHGROUP_INVALID); + LLViewerJointAttachment* pAttachPt = NULL; LLViewerInventoryCategory* pFolder = NULL; LLVector3d posOption; float nOption; + + if (!strOption.empty()) // <option> could be an empty string + { + if (RlvCommandOptionHelper::parseOption(strOption, wtType)) + genericOption = wtType; // ... or specify a (valid) clothing layer + else if (RlvCommandOptionHelper::parseOption(strOption, pAttachPt)) + genericOption = pAttachPt; // ... or specify an attachment point + else if (RlvCommandOptionHelper::parseOption(strOption, idOption)) + genericOption = idOption; // ... or specify an UUID + else if (RlvCommandOptionHelper::parseOption(strOption, pFolder)) + genericOption = pFolder; // ... or specify a shared folder path + else if (RlvCommandOptionHelper::parseOption(strOption, eAttachGroup)) + genericOption = eAttachGroup; // ... or specify an attachment point group + else if (RlvCommandOptionHelper::parseOption(strOption, posOption)) + genericOption = posOption; // ... or specify a vector (region or global coordinates) + else if (RlvCommandOptionHelper::parseOption(strOption, nOption)) + genericOption = nOption; // ... or specify a number + else + genericOption = strOption; // ... or it might just be a string + } + return true; +} + +bool RlvCommandOptionHelper::parseStringList(const std::string& strOption, std::vector<std::string>& optionList, const std::string& strSeparator) +{ + if (!strOption.empty()) + boost::split(optionList, strOption, boost::is_any_of(strSeparator)); + return !optionList.empty(); +} + +// ============================================================================ +// RlvCommandOption structures +// + +// Checked: 2012-07-28 (RLVa-1.4.7) +class RlvCommandOptionGetPathCallback +{ +public: + RlvCommandOptionGetPathCallback(const LLUUID& idAttachObj, RlvCommandOptionGetPath::getpath_callback_t cb) + : mObjectId(idAttachObj), mCallback(cb) + { + if (isAgentAvatarValid()) + mAttachmentConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvCommandOptionGetPathCallback::onAttachment, this, _1, _3)); + gIdleCallbacks.addFunction(&onIdle, this); + } + + ~RlvCommandOptionGetPathCallback() + { + if (mAttachmentConnection.connected()) + mAttachmentConnection.disconnect(); + gIdleCallbacks.deleteFunction(&onIdle, this); + } + + void onAttachment(LLViewerObject* pAttachObj, LLVOAvatarSelf::EAttachAction eAction) + { + if ( (LLVOAvatarSelf::ACTION_ATTACH == eAction) && (pAttachObj->getID() == mObjectId) ) + { + uuid_vec_t idItems(1, pAttachObj->getAttachmentItemID()); + mCallback(idItems); + delete this; + } + } + + static void onIdle(void* pData) + { + RlvCommandOptionGetPathCallback* pInstance = reinterpret_cast<RlvCommandOptionGetPathCallback*>(pData); + if (pInstance->mExpirationTimer.getElapsedTimeF32() > 30.0f) + delete pInstance; + } + +protected: + LLUUID mObjectId; + RlvCommandOptionGetPath::getpath_callback_t mCallback; + boost::signals2::connection mAttachmentConnection; + LLFrameTimer mExpirationTimer; +}; + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b +RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb) + : m_fCallback(false) +{ + m_fValid = true; // Assume the option will be a valid one until we find out otherwise + + // @getpath[:<option>]=<channel> => <option> is transformed to a list of inventory item UUIDs to get the path of + RlvCommandOptionGeneric rlvCmdOption; + RlvCommandOptionHelper::parseOption(rlvCmd.getOption(), rlvCmdOption); + if (rlvCmdOption.isWearableType()) // <option> can be a clothing layer + { + getItemIDs(rlvCmdOption.getWearableType(), m_idItems); + } + else if (rlvCmdOption.isAttachmentPoint()) // ... or it can specify an attachment point + { + getItemIDs(rlvCmdOption.getAttachmentPoint(), m_idItems); + } + else if (rlvCmdOption.isUUID()) // ... or it can specify a specific attachment + { + const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmdOption.getUUID()); + if ( (pAttachObj) && (pAttachObj->isAttachment()) && (pAttachObj->permYouOwner()) ) + m_idItems.push_back(pAttachObj->getAttachmentItemID()); + else + m_fValid = false; + } + else if (rlvCmdOption.isEmpty()) // ... or it can be empty (in which case we act on the object that issued the command) + { + const LLViewerObject* pObj = gObjectList.findObject(rlvCmd.getObjectID()); + if (pObj) + { + if (pObj->isAttachment()) + m_idItems.push_back(pObj->getAttachmentItemID()); + } + else if (!cb.empty()) + { + new RlvCommandOptionGetPathCallback(rlvCmd.getObjectID(), cb); + m_fCallback = true; + return; + } + } + else // ... but anything else isn't a valid option + { + m_fValid = false; + return; + } + + if (!cb.empty()) + { + cb(getItemIDs()); + } +} + +// Checked: 2013-10-12 (RLVa-1.4.9) +bool RlvCommandOptionGetPath::getItemIDs(const LLViewerJointAttachment* pAttachPt, uuid_vec_t& idItems) +{ + uuid_vec_t::size_type cntItemsPrev = idItems.size(); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvFindAttachmentsOnPoint f(pAttachPt); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, false, f); + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem) + idItems.push_back(pItem->getLinkedUUID()); + } + + return (cntItemsPrev != idItems.size()); +} + +// Checked: 2013-10-12 (RLVa-1.4.9) +bool RlvCommandOptionGetPath::getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems) +{ + uuid_vec_t::size_type cntItemsPrev = idItems.size(); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLFindWearablesOfType f(wtType); + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, false, f); + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem) + idItems.push_back(pItem->getLinkedUUID()); + } + + return (cntItemsPrev != idItems.size()); +} + +// Checked: 2015-03-30 (RLVa-1.5.0) +RlvCommandOptionAdjustHeight::RlvCommandOptionAdjustHeight(const RlvCommand& rlvCmd) + : m_nPelvisToFoot(0.0f), m_nPelvisToFootDeltaMult(0.0f), m_nPelvisToFootOffset(0.0f) +{ + std::vector<std::string> cmdTokens; + boost::split(cmdTokens, rlvCmd.getOption(), boost::is_any_of(std::string(";"))); + if (1 == cmdTokens.size()) + { + m_fValid = (LLStringUtil::convertToF32(cmdTokens[0], m_nPelvisToFootOffset)); + m_nPelvisToFootOffset /= 100; + } + else if ( (2 <= cmdTokens.size()) && (cmdTokens.size() <= 3) ) + { + m_fValid = (LLStringUtil::convertToF32(cmdTokens[0], m_nPelvisToFoot)) && + (LLStringUtil::convertToF32(cmdTokens[1], m_nPelvisToFootDeltaMult)) && + ( (2 == cmdTokens.size()) || (LLStringUtil::convertToF32(cmdTokens[2], m_nPelvisToFootOffset)) ); + } +} + +// ========================================================================= +// RlvObject +// + +RlvObject::RlvObject(const LLUUID& idObj) : m_idObj(idObj), m_nLookupMisses(0) +{ + LLViewerObject* pObj = gObjectList.findObject(idObj); + m_fLookup = (NULL != pObj); + m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getAttachmentState()) : 0; + m_idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null; +} + +bool RlvObject::addCommand(const RlvCommand& rlvCmd) +{ + RLV_ASSERT(RLV_TYPE_ADD == rlvCmd.getParamType()); + + // Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on) + for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + { + if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && + (itCmd->isStrict() == rlvCmd.isStrict() ) ) + { + return false; + } + } + + // Now that we know it's not a duplicate, add it to the end of the list + m_Commands.push_back(rlvCmd); + + return true; +} + +bool RlvObject::removeCommand(const RlvCommand& rlvCmd) +{ + RLV_ASSERT(RLV_TYPE_REMOVE == rlvCmd.getParamType()); + + for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + { + //if (*itCmd == rlvCmd) <- commands will never be equal since one is an add and the other is a remove *rolls eyes* + if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && + (itCmd->isStrict() == rlvCmd.isStrict() ) ) + { + m_Commands.erase(itCmd); + return true; + } + } + return false; // Command was never added so nothing to remove now +} + +bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const +{ + for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption().empty()) && ((!fStrictOnly) || (itCmd->isStrict())) ) + return true; + return false; +} + +bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const +{ + for (const RlvCommand& rlvCmd : m_Commands) + { + // The specified behaviour is contained within the current object if: + // - the (parsed) behaviour matches + // - the option matches (or we're checking for an empty option and the command was reference counted) + // - we're not matching on strict (or it is a strict command) + if ( (rlvCmd.getBehaviourType() == eBehaviour) && + ( (rlvCmd.getOption() == strOption) || ((strOption.empty()) && (rlvCmd.isRefCounted())) ) && + ( (!fStrictOnly) ||(rlvCmd.isStrict()) ) ) + { + return true; + } + } + return false; +} + +// Checked: 2009-11-27 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f +std::string RlvObject::getStatusString(const std::string& strFilter, const std::string& strSeparator) const +{ + std::string strStatus, strCmd; + + for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd) + { + strCmd = itCmd->asString(); + if ( (strFilter.empty()) || (std::string::npos != strCmd.find(strFilter)) ) + strStatus.append(strSeparator).append(strCmd); + } + + return strStatus; +} + +// ============================================================================ +// RlvForceWear +// + +RlvForceWear::RlvForceWear() +{ +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +bool RlvForceWear::isWearingItem(const LLInventoryItem* pItem) +{ + if (pItem) + { + switch (pItem->getActualType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + return gAgentWearables.isWearingItem(pItem->getUUID()); + case LLAssetType::AT_OBJECT: + return (isAgentAvatarValid()) && (gAgentAvatarp->isWearingAttachment(pItem->getUUID())); + case LLAssetType::AT_GESTURE: + return LLGestureMgr::instance().isGestureActive(pItem->getUUID()); + case LLAssetType::AT_LINK: + return isWearingItem(gInventory.getItem(pItem->getLinkedUUID())); + default: + break; + } + } + return false; +} + +// Checked: 2010-03-21 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags) +{ + // [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items] + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); + return; + } + if (!isAgentAvatarValid()) + return; + + // Grab a list of all the items we'll be wearing/attaching + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvWearableItemCollector f(pFolder, eAction, eFlags); + gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, true); + + // TRUE if we've already encountered this LLWearableType::EType (used only on wear actions and only for AT_CLOTHING) + bool fSeenWType[LLWearableType::WT_COUNT] = { false }; + + EWearAction eCurAction = eAction; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pRlvItem = items.at(idxItem); + LLViewerInventoryItem* pItem = (LLAssetType::AT_LINK == pRlvItem->getActualType()) ? pRlvItem->getLinkedItem() : pRlvItem; + + // If it's wearable it should be worn on detach +// if ( (ACTION_DETACH == eAction) && (isWearableItem(pItem)) && (!isWearingItem(pItem)) ) +// continue; + + // Each folder can specify its own EWearAction override + if (isWearAction(eAction)) + eCurAction = f.getWearAction(pRlvItem->getParentUUID()); + else + eCurAction = eAction; + + // NOTES: * if there are composite items then RlvWearableItemCollector made sure they can be worn (or taken off depending) + // * some scripts issue @remattach=force,attach:worn-items=force so we need to attach items even if they're currently worn + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + RLV_ASSERT(isWearAction(eAction)); // RlvWearableItemCollector shouldn't be supplying us with body parts on detach + case LLAssetType::AT_CLOTHING: + if (isWearAction(eAction)) + { + // The first time we encounter any given clothing type we use 'eCurAction' (replace or add) + // The second time we encounter a given clothing type we'll always add (rather than replace the previous iteration) + eCurAction = (!fSeenWType[pItem->getWearableType()]) ? eCurAction : ACTION_WEAR_ADD; + + ERlvWearMask eWearMask = gRlvWearableLocks.canWear(pRlvItem); + if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) || + ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) ) + { + // The check for whether we're replacing a currently worn composite item happens in onWearableArrived() + if (!isAddWearable(pItem)) + addWearable(pRlvItem, eCurAction); + fSeenWType[pItem->getWearableType()] = true; + } + } + else + { + const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getUUID()); + if ( (pWearable) && (isForceRemovable(pWearable, false)) ) + remWearable(pWearable); + } + break; + + case LLAssetType::AT_OBJECT: + if (isWearAction(eAction)) + { + ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pRlvItem); + if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) || + ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) ) + { + if (!isAddAttachment(pRlvItem)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // We still need to check whether we're about to replace a currently worn composite item + // (which we're not if we're just reattaching an attachment we're already wearing) + LLViewerInventoryCategory* pCompositeFolder = NULL; + if ( (pAttachPt->getObject()) && (RlvSettings::getEnableComposites()) && + (pAttachPt->getItemID() != pItem->getUUID()) && + (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pCompositeFolder)) ) + { + // If we can't take off the composite folder this item would replace then don't allow it to get attached + if (gRlvHandler.canTakeOffComposite(pCompositeFolder)) + { + forceFolder(pCompositeFolder, ACTION_DETACH, FLAG_DEFAULT); + addAttachment(pRlvItem); + } + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + addAttachment(pRlvItem, eCurAction); + } + } + } + } + else + { + const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(pItem->getUUID()); + if ( (pAttachObj) && (isForceDetachable(pAttachObj, false)) ) + remAttachment(pAttachObj); + } + break; + + case LLAssetType::AT_GESTURE: + if (isWearAction(eAction)) + { + if (std::find_if(m_addGestures.begin(), m_addGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_addGestures.end()) + m_addGestures.push_back(pRlvItem); + } + else + { + if (std::find_if(m_remGestures.begin(), m_remGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_remGestures.end()) + m_remGestures.push_back(pRlvItem); + } + break; + + default: + break; + } + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvForceWear::isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Attachment can be detached by an RLV command if: + // - it's not "remove locked" by anything (or anything except the object specified by pExceptObj) + // - it's strippable + // - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + return + ( + (pAttachObj) && (pAttachObj->isAttachment()) + && ( (idExcept.isNull()) ? (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + : (!gRlvAttachmentLocks.isLockedAttachmentExcept(pAttachObj, idExcept)) ) + && (isStrippable(pAttachObj->getAttachmentItemID())) + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvForceWear::isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Attachment point can be detached by an RLV command if there's at least one attachment that can be removed + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if (isForceDetachable(*itAttachObj, fCheckComposite, idExcept)) + return true; + } + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.1.0i +void RlvForceWear::forceDetach(const LLViewerObject* pAttachObj) +{ + // Sanity check - no need to process duplicate removes + if ( (!pAttachObj) || (isRemAttachment(pAttachObj)) ) + return; + + if (isForceDetachable(pAttachObj)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && + (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) ) + { + // Attachment belongs to a composite folder so detach the entire folder (if we can take it off) + if (gRlvHandler.canTakeOffComposite(pFolder)) + forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + remAttachment(pAttachObj); + } + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvForceWear::forceDetach(const LLViewerJointAttachment* pAttachPt) +{ + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + forceDetach(*itAttachObj); + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a +bool RlvForceWear::isForceRemovable(const LLViewerWearable* pWearable, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Wearable can be removed by an RLV command if: + // - its asset type is AT_CLOTHING + // - it's not "remove locked" by anything (or anything except the object specified by idExcept) + // - it's strippable + // - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + return + ( + (pWearable) && (LLAssetType::AT_CLOTHING == pWearable->getAssetType()) + && ( (idExcept.isNull()) ? !gRlvWearableLocks.isLockedWearable(pWearable) + : !gRlvWearableLocks.isLockedWearableExcept(pWearable, idExcept) ) + && (isStrippable(pWearable->getItemID())) + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + && ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || + (!gRlvHandler.getCompositeInfo(pWearable->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvForceWear::isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/) +{ + // Wearable type can be removed by an RLV command if there's at least one currently worn wearable that can be removed + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++) + if (isForceRemovable(gAgentWearables.getViewerWearable(wtType, idxWearable), fCheckComposite, idExcept)) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvForceWear::forceRemove(const LLViewerWearable* pWearable) +{ + // Sanity check - no need to process duplicate removes + if ( (!pWearable) || (isRemWearable(pWearable)) ) + return; + + if (isForceRemovable(pWearable)) + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && + (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) ) + { + // Wearable belongs to a composite folder so detach the entire folder (if we can take it off) + if (gRlvHandler.canTakeOffComposite(pFolder)) + forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + } + else + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + remWearable(pWearable); + } + } +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvForceWear::forceRemove(LLWearableType::EType wtType) +{ + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++) + forceRemove(gAgentWearables.getViewerWearable(wtType, idxWearable)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a +bool RlvForceWear::isStrippable(const LLInventoryItem* pItem) +{ + // An item is exempt from @detach or @remoutfit if: + // - its name contains "nostrip" (anywhere in the name) + // - its parent folder contains "nostrip" (anywhere in the name) + if (pItem) + { + // If the item is an inventory link then we first examine its target before examining the link itself (and never its name) + if (LLAssetType::AT_LINK == pItem->getActualType()) + { + if (!isStrippable(pItem->getLinkedUUID())) + return false; + } + else + { + if (std::string::npos != pItem->getName().find(RLV_FOLDER_FLAG_NOSTRIP)) + return false; + } + + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + while (pFolder) + { + if (std::string::npos != pFolder->getName().find(RLV_FOLDER_FLAG_NOSTRIP)) + return false; + // If the item's parent is a folded folder then we need to check its parent as well + if ( (gInventory.getRootFolderID() != pFolder->getParentUUID()) && (RlvInventory::isFoldedFolder(pFolder, true)) ) + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + else + pFolder = NULL; + } + } + return true; +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction) +{ + // Remove it from 'm_remAttachments' if it's queued for detaching + const LLViewerObject* pAttachObj = (isAgentAvatarValid()) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL; + if ( (pAttachObj) && (isRemAttachment(pAttachObj)) ) + m_remAttachments.erase(std::remove(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj), m_remAttachments.end()); + + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pItem, true); + if (ACTION_WEAR_ADD == eAction) + { + // Insert it at the back if it's not already there + idxAttachPt |= ATTACHMENT_ADD; + if (!isAddAttachment(pItem)) + { + addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt); + if (itAddAttachments == m_addAttachments.end()) + { + m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t())); + itAddAttachments = m_addAttachments.find(idxAttachPt); + } + itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem); + } + } + else if (ACTION_WEAR_REPLACE == eAction) + { + // Replace all pending attachments on this attachment point with the specified item (don't clear if it's the default attach point) + addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt | ATTACHMENT_ADD); + if ( (0 != idxAttachPt) && (itAddAttachments != m_addAttachments.end()) ) + itAddAttachments->second.clear(); + + itAddAttachments = m_addAttachments.find(idxAttachPt); + if (itAddAttachments == m_addAttachments.end()) + { + m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t())); + itAddAttachments = m_addAttachments.find(idxAttachPt); + } + + if (0 != idxAttachPt) + itAddAttachments->second.clear(); + itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem); + } +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::remAttachment(const LLViewerObject* pAttachObj) +{ + // Remove it from 'm_addAttachments' if it's queued for attaching + const LLViewerInventoryItem* pItem = (pAttachObj->isAttachment()) ? gInventory.getItem(pAttachObj->getAttachmentItemID()) : NULL; + if (pItem) + { + addattachments_map_t::iterator itAddAttachments = m_addAttachments.begin(); + while (itAddAttachments != m_addAttachments.end()) + { + LLInventoryModel::item_array_t& wearItems = itAddAttachments->second; + if (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end()) + wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end()); + + if (wearItems.empty()) + m_addAttachments.erase(itAddAttachments++); + else + ++itAddAttachments; + } + } + + // Add it to 'm_remAttachments' if it's not already there + if (!isRemAttachment(pAttachObj)) + { + m_remAttachments.push_back(const_cast<LLViewerObject*>(pAttachObj)); + } +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction) +{ + const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID()); + // When replacing remove all currently worn wearables of this type *unless* the item is currently worn + if ( (ACTION_WEAR_REPLACE == eAction) && (!pWearable) ) + forceRemove(pItem->getWearableType()); + // Remove it from 'm_remWearables' if it's pending removal + if ( (pWearable) && (isRemWearable(pWearable)) ) + m_remWearables.erase(std::remove(m_remWearables.begin(), m_remWearables.end(), pWearable), m_remWearables.end()); + + addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType()); + if (itAddWearables == m_addWearables.end()) + { + m_addWearables.insert(addwearable_pair_t(pItem->getWearableType(), LLInventoryModel::item_array_t())); + itAddWearables = m_addWearables.find(pItem->getWearableType()); + } + + if (ACTION_WEAR_ADD == eAction) // Add it at the back if it's not already there + { + if (!isAddWearable(pItem)) + itAddWearables->second.push_back((LLViewerInventoryItem*)pItem); + } + else if (ACTION_WEAR_REPLACE == eAction) // Replace all pending wearables of this type with the specified item + { + itAddWearables->second.clear(); + itAddWearables->second.push_back((LLViewerInventoryItem*)pItem); + } +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +void RlvForceWear::remWearable(const LLViewerWearable* pWearable) +{ + // Remove it from 'm_addWearables' if it's queued for wearing + const LLViewerInventoryItem* pItem = gInventory.getItem(pWearable->getItemID()); + if ( (pItem) && (isAddWearable(pItem)) ) + { + addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType()); + + LLInventoryModel::item_array_t& wearItems = itAddWearables->second; + wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end()); + if (wearItems.empty()) + m_addWearables.erase(itAddWearables); + } + + // Add it to 'm_remWearables' if it's not already there + if (!isRemWearable(pWearable)) + m_remWearables.push_back(pWearable); +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::updatePendingAttachments() +{ + if (RlvForceWear::instanceExists()) + { + RlvForceWear* pThis = RlvForceWear::getInstance(); + for (const pendingattachments_map_t::value_type& itAttach : pThis->m_pendingAttachments) + LLAttachmentsMgr::instance().addAttachmentRequest(itAttach.first, itAttach.second & ~ATTACHMENT_ADD, itAttach.second & ATTACHMENT_ADD); + pThis->m_pendingAttachments.clear(); + } +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::addPendingAttachment(const LLUUID& idItem, U8 idxPoint) +{ + auto itAttach = m_pendingAttachments.find(idItem); + if (m_pendingAttachments.end() == itAttach) + m_pendingAttachments.insert(std::make_pair(idItem, idxPoint)); + else + itAttach->second = idxPoint; +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::remPendingAttachment(const LLUUID& idItem) +{ + m_pendingAttachments.erase(idItem); +} + +// Checked: 2015-05-05 (RLVa-1.4.12) +void RlvForceWear::done() +{ + // Sanity check - don't go through all the motions below only to find out there's nothing to actually do + if ( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) && + (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) ) + { + return; + } + + // + // Process removals + // + + uuid_vec_t remItems; + + // Wearables + if (m_remWearables.size()) + { + for (const LLViewerWearable* pWearable : m_remWearables) + remItems.push_back(pWearable->getItemID()); + m_remWearables.clear(); + } + + // Gestures + if (m_remGestures.size()) + { + // NOTE: LLGestureMgr::deactivateGesture() will call LLAppearanceMgr::removeCOFItemLinks() for us and supply its own callback + for (const LLViewerInventoryItem* pItem : m_remGestures) + LLGestureMgr::instance().deactivateGesture(pItem->getUUID()); + m_remGestures.clear(); + } + + // Attachments + if (m_remAttachments.size()) + { + LLAgentWearables::userRemoveMultipleAttachments(m_remAttachments); + for (const LLViewerObject* pAttachObj : m_remAttachments) + remItems.push_back(pAttachObj->getAttachmentItemID()); + m_remAttachments.clear(); + } + + // + // Process additions + // + + // Wearables need to be split into AT_BODYPART and AT_CLOTHING for COF + LLInventoryModel::item_array_t addBodyParts, addClothing; + for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.cbegin(); itAddWearables != m_addWearables.cend(); ++itAddWearables) + { + // NOTE: LLAppearanceMgr will filter our duplicates so no need for us to check here + for (LLViewerInventoryItem* pItem : itAddWearables->second) + { + if (LLAssetType::AT_BODYPART == pItem->getType()) + addBodyParts.push_back(pItem); + else + addClothing.push_back(pItem); + } + } + m_addWearables.clear(); + + // Until LL provides a way for updateCOF to selectively attach add/replace we have to deal with attachments ourselves + for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.cbegin(); itAddAttachments != m_addAttachments.cend(); ++itAddAttachments) + { + for (const LLViewerInventoryItem* pItem : itAddAttachments->second) + addPendingAttachment(pItem->getLinkedUUID(), itAddAttachments->first); + } + m_addAttachments.clear(); + + // + // Tie it all together + // + + // | Wearables | Attachments | Gestures | + // |======================================================| + // Add : | LLAppearanceMgr | <custom> | LLAppearanceMgr | + // Remove : | LLAppearanceMgr | LLAppearanceMgr | LLGestureMgr | + LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(false, false, boost::bind(RlvForceWear::updatePendingAttachments)); + + if (!remItems.empty()) + { + LLAppearanceMgr::instance().removeItemsFromAvatar(remItems, cb, true); + } + + if ( (addBodyParts.empty()) && (!addClothing.empty()) && (m_addGestures.empty()) ) + { + // Clothing items only + uuid_vec_t idClothing; + for (const LLViewerInventoryItem* pItem : addClothing) + idClothing.push_back(pItem->getUUID()); + LLAppearanceMgr::instance().wearItemsOnAvatar(idClothing, false, false, cb); + } + else if ( (!addBodyParts.empty()) || (!addClothing.empty()) || (!m_addGestures.empty()) ) + { + // Mixture of body parts, clothing and/or gestures + LLInventoryModel::item_array_t addAttachments; + LLAppearanceMgr::instance().updateCOF(addBodyParts, addClothing, addAttachments, m_addGestures, true, LLUUID::null, cb); + + m_addGestures.clear(); + } + + // Make sure there are no leftovers for the next cycle + RLV_ASSERT( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) ); + RLV_ASSERT( (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) ); +} + +// Checked: 2010-02-17 (RLVa-1.1.0o) | Modified: RLVa-1.1.0o +/* +void RlvForceWear::onWearableArrived(LLWearable* pWearable, void* pParam) +{ + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + // If this wearable will end up replacing a currently worn one that belongs to a composite folder then we need to detach the composite + LLViewerInventoryCategory* pFolder = NULL; + if ( (RlvSettings::getEnableComposites()) && (pWearable) && (gAgent.getWearable(pWearable->getType())) ) + { + // If we're just rewearing the same item we're already wearing then we're not replacing a composite folder + LLWearableHoldingPattern* pWearData = (LLWearableHoldingPattern*)pParam; LLUUID idItem; + for (LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin(); + itWearable != pWearData->mFoundList.end(); ++itWearable) + { + LLFoundData* pFound = *itWearable; + if (pWearable->getID() == pFound->mAssetID) + { + idItem = pFound->mItemID; + break; + } + } + if ( (idItem.notNull()) && (idItem != gAgent.getWearableItem(pWearable->getType())) && + (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(pWearable->getType()), NULL, &pFolder)) ) + { + RlvForceWear rlvWear; + rlvWear.forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT); + rlvWear.done(); + } + } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + wear_inventory_category_on_avatar_loop(pWearable, pParam); +} +*/ + +// ============================================================================ +// RlvBehaviourNotifyObserver +// + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +RlvBehaviourNotifyHandler::RlvBehaviourNotifyHandler() +{ + // NOTE: the reason we use rlv_command_signal_t instead of the better-suited rlv_behaviour_signal_t is because + // RLV will notify scripts about "invalid" commands so we need to as well + m_ConnCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvBehaviourNotifyHandler::onCommand, this, _1, _2, _3)); +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvBehaviourNotifyHandler::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal) +{ + if (fInternal) + return; + + switch (rlvCmd.getParamType()) + { + case RLV_TYPE_ADD: + case RLV_TYPE_REMOVE: + sendNotification(rlvCmd.asString(), "=" + rlvCmd.getParam()); + break; + case RLV_TYPE_CLEAR: + sendNotification(rlvCmd.asString()); + break; + default: + break; + } +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Modify: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::sendNotification(const std::string& strText, const std::string& strSuffix) +{ + if (instanceExists()) + { + RlvBehaviourNotifyHandler* pThis = getInstance(); + + // NOTE: notifications have two parts (which are concatenated without token) where only the first part is subject to the filter + for (std::multimap<LLUUID, notifyData>::const_iterator itNotify = pThis->m_Notifications.begin(); + itNotify != pThis->m_Notifications.end(); ++itNotify) + { + if ( (itNotify->second.strFilter.empty()) || (boost::icontains(strText, itNotify->second.strFilter)) ) + RlvUtil::sendChatReply(itNotify->second.nChannel, "/" + strText + strSuffix); + } + } +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onWear(LLWearableType::EType eType, bool fAllowed) +{ + sendNotification(llformat("worn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onTakeOff(LLWearableType::EType eType, bool fAllowed) +{ + sendNotification(llformat("unworn %s %s", (fAllowed) ? "legally" : "illegally", LLWearableType::getTypeName(eType).c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onAttach(const LLViewerJointAttachment* pAttachPt, bool fAllowed) +{ + sendNotification(llformat("attached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onDetach(const LLViewerJointAttachment* pAttachPt, bool fAllowed) +{ + sendNotification(llformat("detached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str())); +} + +// Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +void RlvBehaviourNotifyHandler::onReattach(const LLViewerJointAttachment* pAttachPt, bool fAllowed) +{ + sendNotification(llformat("reattached %s %s", (fAllowed) ? "legally" : "illegally", pAttachPt->getName().c_str())); +} + +// ========================================================================= +// Various helper classes/timers/functors +// + +// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +BOOL RlvGCTimer::tick() +{ + bool fContinue = gRlvHandler.onGC(); + if (!fContinue) + gRlvHandler.m_pGCTimer = NULL; + return !fContinue; +} + +// ============================================================================ +// Various helper functions +// + +// ============================================================================ +// Attachment group helper functions +// + +// Has to match the order of ERlvAttachGroupType +const std::string cstrAttachGroups[RLV_ATTACHGROUP_COUNT] = { "head", "torso", "arms", "legs", "hud" }; + +// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e +ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup) +{ + switch (idxGroup) + { + case 0: // Right Hand + case 1: // Right Arm + case 3: // Left Arm + case 4: // Left Hand + return RLV_ATTACHGROUP_ARMS; + case 2: // Head + return RLV_ATTACHGROUP_HEAD; + case 5: // Left Leg + case 7: // Right Leg + return RLV_ATTACHGROUP_LEGS; + case 6: // Torso + return RLV_ATTACHGROUP_TORSO; + case 8: // HUD + return RLV_ATTACHGROUP_HUD; + default: + return RLV_ATTACHGROUP_INVALID; + } +} + +// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e +ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup) +{ + for (int idx = 0; idx < RLV_ATTACHGROUP_COUNT; idx++) + if (cstrAttachGroups[idx] == strGroup) + return (ERlvAttachGroupType)idx; + return RLV_ATTACHGROUP_INVALID; +} + +// ========================================================================= +// String helper functions +// + +// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b +std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch /*=NULL*/) +{ + if (pidxMatch) + *pidxMatch = std::string::npos; // Assume we won't find anything + + std::string::size_type idxIt, idxStart; int cntLevel = 1; + if ((idxStart = strText.find_first_of('(')) == std::string::npos) + return std::string(); + + const char* pstrText = strText.c_str(); idxIt = idxStart; + while ( (cntLevel > 0) && (++idxIt < strText.length()) ) + { + if ('(' == pstrText[idxIt]) + cntLevel++; + else if (')' == pstrText[idxIt]) + cntLevel--; + } + + if (idxIt < strText.length()) + { + if (pidxMatch) + *pidxMatch = idxStart; // Return the character index of the starting '(' + return strText.substr(idxStart + 1, idxIt - idxStart - 1); + } + return std::string(); +} + +// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b +std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart /*=NULL*/) +{ + if (pidxStart) + *pidxStart = std::string::npos; // Assume we won't find anything + + // Extracts the last - matched - parenthesised text from the input string + std::string::size_type idxIt, idxEnd; int cntLevel = 1; + if ((idxEnd = strText.find_last_of(')')) == std::string::npos) + return std::string(); + + const char* pstrText = strText.c_str(); idxIt = idxEnd; + while ( (cntLevel > 0) && (--idxIt >= 0) && (idxIt < strText.length()) ) + { + if (')' == pstrText[idxIt]) + cntLevel++; + else if ('(' == pstrText[idxIt]) + cntLevel--; + } + + if ( (idxIt >= 0) && (idxIt < strText.length()) ) // NOTE: allow for std::string::size_type to be signed or unsigned + { + if (pidxStart) + *pidxStart = idxIt; // Return the character index of the starting '(' + return strText.substr(idxIt + 1, idxEnd - idxIt - 1); + } + return std::string(); +} + +// ========================================================================= diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h new file mode 100644 index 0000000000000000000000000000000000000000..6cf2c5c62ebc886f22ba952ffb039e75dc212fe3 --- /dev/null +++ b/indra/newview/rlvhelper.h @@ -0,0 +1,724 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_HELPER_H +#define RLV_HELPER_H + +#include "lleventtimer.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" +#include "llwearabletype.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// Forward declarations +// + +class RlvBehaviourModifier; +struct RlvBehaviourModifierComp; + +// ============================================================================ +// RlvBehaviourInfo class - Generic behaviour descriptor (used by restrictions, reply and force commands) +// + +class RlvBehaviourInfo +{ +public: + enum EBehaviourFlags + { + // General behaviour flags + BHVR_STRICT = 0x0001, // Behaviour has a "_sec" version + BHVR_SYNONYM = 0x0002, // Behaviour is a synonym of another + BHVR_EXTENDED = 0x0004, // Behaviour is part of the RLVa extended command set + BHVR_EXPERIMENTAL = 0x0008, // Behaviour is part of the RLVa experimental command set + BHVR_BLOCKED = 0x0010, // Behaviour is blocked + BHVR_DEPRECATED = 0x0020, // Behaviour is deprecated + BHVR_GENERAL_MASK = 0x0FFF, + + // Force-wear specific flags + FORCEWEAR_WEAR_REPLACE = 0x0001 << 16, + FORCEWEAR_WEAR_ADD = 0x0002 << 16, + FORCEWEAR_WEAR_REMOVE = 0x0004 << 16, + FORCEWEAR_NODE = 0x0010 << 16, + FORCEWEAR_SUBTREE = 0x0020 << 16, + FORCEWEAR_CONTEXT_NONE = 0x0100 << 16, + FORCEWEAR_CONTEXT_OBJECT = 0x0200 << 16, + FORCEWEAR_MASK = 0xFFFF << 16 + }; + + RlvBehaviourInfo(std::string strBhvr, ERlvBehaviour eBhvr, U32 maskParamType, U32 nBhvrFlags = 0) + : m_strBhvr(strBhvr), m_eBhvr(eBhvr), m_maskParamType(maskParamType), m_nBhvrFlags(nBhvrFlags) {} + virtual ~RlvBehaviourInfo() {} + + const std::string& getBehaviour() const { return m_strBhvr; } + ERlvBehaviour getBehaviourType() const { return m_eBhvr; } + U32 getBehaviourFlags() const { return m_nBhvrFlags; } + U32 getParamTypeMask() const { return m_maskParamType; } + bool hasStrict() const { return m_nBhvrFlags & BHVR_STRICT; } + bool isBlocked() const { return m_nBhvrFlags & BHVR_BLOCKED; } + bool isExperimental() const { return m_nBhvrFlags & BHVR_EXPERIMENTAL; } + bool isExtended() const { return m_nBhvrFlags & BHVR_EXTENDED; } + bool isSynonym() const { return m_nBhvrFlags & BHVR_SYNONYM; } + void toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable); + + virtual ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const { return RLV_RET_NO_PROCESSOR; } + +protected: + std::string m_strBhvr; + ERlvBehaviour m_eBhvr; + U32 m_nBhvrFlags; + U32 m_maskParamType; +}; + +// ============================================================================ +// RlvBehaviourDictionary and related classes +// + +class RlvBehaviourDictionary : public LLSingleton<RlvBehaviourDictionary> +{ + friend class RlvFloaterBehaviours; + LLSINGLETON(RlvBehaviourDictionary); +protected: + ~RlvBehaviourDictionary(); +public: + void addEntry(const RlvBehaviourInfo* pBhvrEntry); + void addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry); + void addModifier(const RlvBehaviourInfo* pBhvrEntry, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry); + + /* + * General helper functions + */ +public: + void clearModifiers(const LLUUID& idRlvObj); + ERlvBehaviour getBehaviourFromString(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; + const RlvBehaviourInfo* getBehaviourInfo(const std::string& strBhvr, ERlvParamType eParamType, bool* pfStrict = NULL) const; + bool getCommands(const std::string& strMatch, ERlvParamType eParamType, std::list<std::string>& cmdList) const; + bool getHasStrict(ERlvBehaviour eBhvr) const; + RlvBehaviourModifier* getModifier(ERlvBehaviourModifier eBhvrMod) const { return (eBhvrMod < RLV_MODIFIER_COUNT) ? m_BehaviourModifiers[eBhvrMod] : nullptr; } + RlvBehaviourModifier* getModifierFromBehaviour(ERlvBehaviour eBhvr) const; + void toggleBehaviourFlag(const std::string& strBhvr, ERlvParamType eParamType, RlvBehaviourInfo::EBehaviourFlags eBvhrFlag, bool fEnable); + + /* + * Member variables + */ +protected: + typedef std::list<const RlvBehaviourInfo*> rlv_bhvrinfo_list_t; + typedef std::map<std::pair<std::string, ERlvParamType>, const RlvBehaviourInfo*> rlv_string2info_map_t; + typedef std::multimap<ERlvBehaviour, const RlvBehaviourInfo*> rlv_bhvr2info_map_t; + typedef std::map<ERlvBehaviour, ERlvBehaviourModifier> rlv_bhvr2mod_map_t; + + rlv_bhvrinfo_list_t m_BhvrInfoList; + rlv_string2info_map_t m_String2InfoMap; + rlv_bhvr2info_map_t m_Bhvr2InfoMap; + rlv_bhvr2mod_map_t m_Bhvr2ModifierMap; + RlvBehaviourModifier* m_BehaviourModifiers[RLV_MODIFIER_COUNT]; +}; + +// ============================================================================ +// RlvCommandHandler and related classes +// + +typedef ERlvCmdRet(RlvBhvrHandlerFunc)(const RlvCommand&, bool&); +typedef void(RlvBhvrToggleHandlerFunc)(ERlvBehaviour, bool); +typedef ERlvCmdRet(RlvForceHandlerFunc)(const RlvCommand&); +typedef ERlvCmdRet(RlvReplyHandlerFunc)(const RlvCommand&, std::string&); + +// +// RlvCommandHandlerBaseImpl - Base implementation for each command type (the old process(AddRem|Force|Reply)Command functions) +// +template<ERlvParamType paramType> struct RlvCommandHandlerBaseImpl; +template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM> { static ERlvCmdRet processCommand(const RlvCommand&, RlvBhvrHandlerFunc*, RlvBhvrToggleHandlerFunc* = nullptr); }; +template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_FORCE> { static ERlvCmdRet processCommand(const RlvCommand&, RlvForceHandlerFunc*); }; +template<> struct RlvCommandHandlerBaseImpl<RLV_TYPE_REPLY> { static ERlvCmdRet processCommand(const RlvCommand&, RlvReplyHandlerFunc*); +}; + +// +// RlvCommandHandler - The actual command handler (Note that a handler is more general than a processor; a handler can - for instance - be used by multiple processors) +// +#if LL_WINDOWS + #define RLV_TEMPL_FIX(x) template<x> +#else + #define RLV_TEMPL_FIX(x) template<typename Placeholder = int> +#endif // LL_WINDOWS + +template <ERlvParamType templParamType, ERlvBehaviour templBhvr> +struct RlvCommandHandler +{ + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_ADDREM>::type) static ERlvCmdRet onCommand(const RlvCommand&, bool&); + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_ADDREM>::type) static void onCommandToggle(ERlvBehaviour, bool); + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_FORCE>::type) static ERlvCmdRet onCommand(const RlvCommand&); + RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == RLV_TYPE_REPLY>::type) static ERlvCmdRet onCommand(const RlvCommand&, std::string&); +}; + +// Aliases to improve readability in definitions +template<ERlvBehaviour templBhvr> using RlvBehaviourHandler = RlvCommandHandler<RLV_TYPE_ADDREM, templBhvr>; +template<ERlvBehaviour templBhvr> using RlvBehaviourToggleHandler = RlvBehaviourHandler<templBhvr>; +template<ERlvBehaviour templBhvr> using RlvForceHandler = RlvCommandHandler<RLV_TYPE_FORCE, templBhvr>; +template<ERlvBehaviour templBhvr> using RlvReplyHandler = RlvCommandHandler<RLV_TYPE_REPLY, templBhvr>; + +// List of shared handlers +typedef RlvBehaviourToggleHandler<RLV_BHVR_SETCAM_EYEOFFSET> RlvBehaviourCamEyeFocusOffsetHandler; // Shared between @setcam_eyeoffset and @setcam_focusoffset +typedef RlvBehaviourHandler<RLV_BHVR_REMATTACH> RlvBehaviourAddRemAttachHandler; // Shared between @addattach and @remattach +typedef RlvBehaviourHandler<RLV_BHVR_SENDCHANNEL> RlvBehaviourSendChannelHandler; // Shared between @sendchannel and @sendchannel_except +typedef RlvBehaviourHandler<RLV_BHVR_SENDIM> RlvBehaviourRecvSendStartIMHandler; // Shared between @recvim, @sendim and @startim +typedef RlvBehaviourHandler<RLV_BHVR_SETCAM_FOVMIN> RlvBehaviourSetCamFovHandler; // Shared between @setcam_fovmin and @setcam_fovmax +typedef RlvBehaviourToggleHandler<RLV_BHVR_SHOWSELF> RlvBehaviourShowSelfToggleHandler; // Shared between @showself and @showselfhead +typedef RlvBehaviourHandler<RLV_BHVR_CAMZOOMMIN> RlvBehaviourCamZoomMinMaxHandler; // Shared between @camzoommin and @camzoommax (deprecated) +typedef RlvReplyHandler<RLV_BHVR_GETCAM_AVDISTMIN> RlvReplyCamMinMaxModifierHandler; // Shared between @getcam_avdistmin and @getcam_avdistmax +typedef RlvForceHandler<RLV_BHVR_REMATTACH> RlvForceRemAttachHandler; // Shared between @remattach and @detach +typedef RlvForceHandler<RLV_BHVR_SETCAM_EYEOFFSET> RlvForceCamEyeFocusOffsetHandler; // Shared between @setcam_eyeoffset and @setcam_focusoffset + +// +// RlvCommandProcessor - Templated glue class that brings RlvBehaviourInfo, RlvCommandHandlerBaseImpl and RlvCommandHandler together +// +template <ERlvParamType templParamType, ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<templParamType, templBhvr>, typename baseImpl = RlvCommandHandlerBaseImpl<templParamType>> +class RlvCommandProcessor : public RlvBehaviourInfo +{ +public: + // Default constructor used by behaviour specializations + RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr != RLV_BHVR_UNKNOWN>::type) + RlvCommandProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, templBhvr, templParamType, nBhvrFlags) {} + + // Constructor used when we don't want to specialize on behaviour (see RlvBehaviourGenericProcessor) + RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr == RLV_BHVR_UNKNOWN>::type) + RlvCommandProcessor(const std::string& strBhvr, ERlvBehaviour eBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, eBhvr, templParamType, nBhvrFlags) {} + + ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return baseImpl::processCommand(rlvCmd, &handlerImpl::onCommand); } +}; + +// Aliases to improve readability in definitions +template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_ADDREM, templBhvr>> using RlvBehaviourProcessor = RlvCommandProcessor<RLV_TYPE_ADDREM, templBhvr, handlerImpl>; +template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_FORCE, templBhvr>> using RlvForceProcessor = RlvCommandProcessor<RLV_TYPE_FORCE, templBhvr, handlerImpl>; +template<ERlvBehaviour templBhvr, typename handlerImpl = RlvCommandHandler<RLV_TYPE_REPLY, templBhvr>> using RlvReplyProcessor = RlvCommandProcessor<RLV_TYPE_REPLY, templBhvr, handlerImpl>; + +// Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense) +template<ERlvBehaviourOptionType templOptionType> struct RlvBehaviourGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); }; +template<ERlvBehaviourOptionType templOptionType> using RlvBehaviourGenericProcessor = RlvBehaviourProcessor<RLV_BHVR_UNKNOWN, RlvBehaviourGenericHandler<templOptionType>>; +template<ERlvBehaviourOptionType templOptionType> struct RlvForceGenericHandler { static ERlvCmdRet onCommand(const RlvCommand& rlvCmd); }; +template<ERlvBehaviourOptionType templOptionType> using RlvForceGenericProcessor = RlvForceProcessor<RLV_BHVR_UNKNOWN, RlvForceGenericHandler<templOptionType>>; + +// ============================================================================ +// RlvBehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions) +// + +template <ERlvBehaviour eBhvr, typename handlerImpl = RlvBehaviourHandler<eBhvr>, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>> +class RlvBehaviourToggleProcessor : public RlvBehaviourInfo +{ +public: + RlvBehaviourToggleProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : RlvBehaviourInfo(strBhvr, eBhvr, RLV_TYPE_ADDREM, nBhvrFlags) {} + ERlvCmdRet processCommand(const RlvCommand& rlvCmd) const override { return RlvCommandHandlerBaseImpl<RLV_TYPE_ADDREM>::processCommand(rlvCmd, &handlerImpl::onCommand, &toggleHandlerImpl::onCommandToggle); } +}; +template <ERlvBehaviour eBhvr, ERlvBehaviourOptionType optionType, typename toggleHandlerImpl = RlvBehaviourToggleHandler<eBhvr>> using RlvBehaviourGenericToggleProcessor = RlvBehaviourToggleProcessor<eBhvr, RlvBehaviourGenericHandler<optionType>, toggleHandlerImpl>; + +// ============================================================================ +// RlvBehaviourModifier - stores behaviour modifiers in an - optionally - sorted list and returns the first element (or default value if there are no modifiers) +// + +typedef std::tuple<RlvBehaviourModifierValue, LLUUID, ERlvBehaviour> RlvBehaviourModifierValueTuple; + +class RlvBehaviourModifier +{ +public: + RlvBehaviourModifier(const std::string strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifierComp* pValueComparator = nullptr); + virtual ~RlvBehaviourModifier(); + + /* + * Member functions + */ +protected: + virtual void onValueChange() const {} +public: + bool addValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN); + bool convertOptionValue(const std::string& optionValue, RlvBehaviourModifierValue& modValue) const; + void clearValues(const LLUUID& idRlvObj); + bool getAddDefault() const { return m_fAddDefaultOnEmpty; } + const RlvBehaviourModifierValue& getDefaultValue() const { return m_DefaultValue; } + const LLUUID& getPrimaryObject() const; + const std::string& getName() const { return m_strName; } + const RlvBehaviourModifierValue& getValue() const { return (hasValue()) ? std::get<0>(m_Values.front()) : m_DefaultValue; } + template<typename T> const T& getValue() const { return boost::get<T>(getValue()); } + bool hasValue() const; + bool hasValue(const LLUUID& idRlvObj) const; + void removeValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj, ERlvBehaviour eBhvr = RLV_BHVR_UNKNOWN); + void setValue(const RlvBehaviourModifierValue& modValue, const LLUUID& idRlvObj); + void setPrimaryObject(const LLUUID& idPrimaryObject); + + typedef boost::signals2::signal<void(const RlvBehaviourModifierValue& newValue)> change_signal_t; + change_signal_t& getSignal() { return m_ChangeSignal; } + + /* + * Member variables + */ +protected: + std::string m_strName; + RlvBehaviourModifierValue m_DefaultValue; + bool m_fAddDefaultOnEmpty; + std::list<RlvBehaviourModifierValueTuple> m_Values; + change_signal_t m_ChangeSignal; + RlvBehaviourModifierComp* m_pValueComparator; +}; + +// ============================================================================ +// RlvCommand +// + +class RlvCommand +{ +public: + explicit RlvCommand(const LLUUID& idObj, const std::string& strCommand); + RlvCommand(const RlvCommand& rlvCmd, ERlvParamType eParamType = RLV_TYPE_UNKNOWN); + + /* + * Member functions + */ +public: + std::string asString() const; + const std::string& getBehaviour() const { return m_strBehaviour; } + ERlvBehaviour getBehaviourType() const { return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourType() : RLV_BHVR_UNKNOWN; } + U32 getBehaviourFlags() const{ return (m_pBhvrInfo) ? m_pBhvrInfo->getBehaviourFlags() : 0; } + const LLUUID& getObjectID() const { return m_idObj; } + const std::string& getOption() const { return m_strOption; } + const std::string& getParam() const { return m_strParam; } + ERlvParamType getParamType() const { return m_eParamType; } + bool hasOption() const { return !m_strOption.empty(); } + bool isBlocked() const { return (m_pBhvrInfo) ? m_pBhvrInfo->isBlocked() : false; } + bool isRefCounted() const { return m_fRefCounted; } + bool isStrict() const { return m_fStrict; } + bool isValid() const { return m_fValid; } + ERlvCmdRet processCommand() const { return (m_pBhvrInfo) ? m_pBhvrInfo->processCommand(*this) : RLV_RET_NO_PROCESSOR; } + +protected: + static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam); + bool markRefCounted() const { return m_fRefCounted = true; } + + /* + * Operators + */ +public: + bool operator ==(const RlvCommand&) const; + + /* + * Member variables + */ +protected: + bool m_fValid; + LLUUID m_idObj; + std::string m_strBehaviour; + const RlvBehaviourInfo* m_pBhvrInfo; + ERlvParamType m_eParamType; + bool m_fStrict; + std::string m_strOption; + std::string m_strParam; + mutable bool m_fRefCounted; + + friend class RlvHandler; + friend class RlvObject; + template<ERlvParamType> friend struct RlvCommandHandlerBaseImpl; +}; + +// ============================================================================ +// Command option parsing utility classes +// + +class RlvCommandOptionHelper +{ +public: + // NOTE: this function is destructive (reference value may still change on parsing failure) + template<typename T> static bool parseOption(const std::string& strOption, T& valueOption); + template<typename T> static T parseOption(const std::string& strOption) + { + T value; + parseOption<T>(strOption, value); + return value; + } + static bool parseStringList(const std::string& strOption, std::vector<std::string>& optionList, const std::string& strSeparator = std::string(RLV_OPTION_SEPARATOR)); +}; + +struct RlvCommandOptionGeneric +{ + bool isAttachmentPoint() const { return (!isEmpty()) && (typeid(LLViewerJointAttachment*) == m_varOption.type()); } + bool isAttachmentPointGroup() const { return (!isEmpty()) && (typeid(ERlvAttachGroupType) == m_varOption.type()); } + bool isEmpty() const { return typeid(boost::blank) == m_varOption.type(); } + bool isNumber() const { return (!isEmpty()) && (typeid(float) == m_varOption.type()); } + bool isSharedFolder() const { return (!isEmpty()) && (typeid(LLViewerInventoryCategory*) == m_varOption.type()); } + bool isString() const { return (!isEmpty()) && (typeid(std::string) == m_varOption.type()); } + bool isUUID() const { return (!isEmpty()) && (typeid(LLUUID) == m_varOption.type()); } + bool isVector() const { return (!isEmpty()) && (typeid(LLVector3d) == m_varOption.type()); } + bool isWearableType() const { return (!isEmpty()) && (typeid(LLWearableType::EType) == m_varOption.type()); } + + LLViewerJointAttachment* getAttachmentPoint() const { return (isAttachmentPoint()) ? boost::get<LLViewerJointAttachment*>(m_varOption) : NULL; } + ERlvAttachGroupType getAttachmentPointGroup() const { return (isAttachmentPointGroup()) ? boost::get<ERlvAttachGroupType>(m_varOption) : RLV_ATTACHGROUP_INVALID; } + LLViewerInventoryCategory* getSharedFolder() const { return (isSharedFolder()) ? boost::get<LLViewerInventoryCategory*>(m_varOption) : NULL; } + float getNumber() const { return (isNumber()) ? boost::get<float>(m_varOption) : 0.0f; } + const std::string& getString() const { return (isString()) ? boost::get<std::string>(m_varOption) : LLStringUtil::null; } + const LLUUID& getUUID() const { return (isUUID()) ? boost::get<LLUUID>(m_varOption) : LLUUID::null; } + const LLVector3d& getVector() const { return (isVector()) ? boost::get<LLVector3d>(m_varOption) : LLVector3d::zero; } + LLWearableType::EType getWearableType() const { return (isWearableType()) ? boost::get<LLWearableType::EType>(m_varOption) : LLWearableType::WT_INVALID; } + + typedef boost::variant<boost::blank, LLViewerJointAttachment*, ERlvAttachGroupType, LLViewerInventoryCategory*, std::string, LLUUID, LLWearableType::EType, LLVector3d, float> rlv_option_generic_t; + void operator=(const rlv_option_generic_t& optionValue) { m_varOption = optionValue; } +protected: + rlv_option_generic_t m_varOption; +}; + +// ============================================================================ +// Command option parsing utility classes (these still need refactoring to fit the new methodology) +// + +struct RlvCommandOption +{ +protected: + RlvCommandOption() : m_fValid(false) {} +public: + virtual ~RlvCommandOption() {} + +public: + virtual bool isEmpty() const { return false; } + virtual bool isValid() const { return m_fValid; } +protected: + bool m_fValid; +}; + +struct RlvCommandOptionGetPath : public RlvCommandOption +{ + typedef boost::function<void(const uuid_vec_t&)> getpath_callback_t; + RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb = NULL); + + bool isCallback() const { return m_fCallback; } + /*virtual*/ bool isEmpty() const { return m_idItems.empty(); } + const uuid_vec_t& getItemIDs() const { return m_idItems; } + + // NOTE: Both functions are COF-based rather than items gathered from mAttachedObjects or gAgentWearables + static bool getItemIDs(const LLViewerJointAttachment* pAttachPt, uuid_vec_t& idItems); + static bool getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems); + +protected: + bool m_fCallback; // TRUE if a callback is schedueled + uuid_vec_t m_idItems; +}; + +struct RlvCommandOptionAdjustHeight : public RlvCommandOption +{ + RlvCommandOptionAdjustHeight(const RlvCommand& rlvCmd); + + F32 m_nPelvisToFoot; + F32 m_nPelvisToFootDeltaMult; + F32 m_nPelvisToFootOffset; +}; + +// ============================================================================ +// RlvObject +// + +class RlvObject +{ +public: + RlvObject(const LLUUID& idObj); + + /* + * Member functions + */ +public: + bool addCommand(const RlvCommand& rlvCmd); + bool removeCommand(const RlvCommand& rlvCmd); + + std::string getStatusString(const std::string& strFilter, const std::string& strSeparator) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const; + bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const; + + + /* + * Accessors + */ +public: + S32 getAttachPt() const { return m_idxAttachPt; } + const LLUUID& getObjectID() const { return m_idObj; } + const LLUUID& getRootID() const { return m_idRoot; } + bool hasLookup() const { return m_fLookup; } + const rlv_command_list_t& getCommandList() const { return m_Commands; } + + /* + * Member variables + */ +protected: + S32 m_idxAttachPt; // The object's attachment point (or 0 if it's not an attachment) + LLUUID m_idObj; // The object's UUID + LLUUID m_idRoot; // The UUID of the object's root (may or may not be different from m_idObj) + bool m_fLookup; // TRUE if the object existed in gObjectList at one point in time + S16 m_nLookupMisses; // Count of unsuccessful lookups in gObjectList by the GC + rlv_command_list_t m_Commands; // List of behaviours held by this object (in the order they were received) + + friend class RlvHandler; +}; + +// ============================================================================ +// RlvForceWear +// + +class RlvForceWear : public LLSingleton<RlvForceWear> +{ + LLSINGLETON(RlvForceWear); +public: + // Folders + enum EWearAction { ACTION_WEAR_REPLACE, ACTION_WEAR_ADD, ACTION_REMOVE }; + enum EWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE }; + void forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags); + + // Generic + static bool isWearAction(EWearAction eAction) { return (ACTION_WEAR_REPLACE == eAction) || (ACTION_WEAR_ADD == eAction); } + static bool isWearableItem(const LLInventoryItem* pItem); + static bool isWearingItem(const LLInventoryItem* pItem); + + // Nostrip + static bool isStrippable(const LLUUID& idItem) { return isStrippable(gInventory.getItem(idItem)); } + static bool isStrippable(const LLInventoryItem* pItem); + + // Attachments + static bool isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + static bool isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + void forceDetach(const LLViewerObject* pAttachObj); + void forceDetach(const LLViewerJointAttachment* ptAttachPt); + + // Wearables + static bool isForceRemovable(const LLViewerWearable* pWearable, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + static bool isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null); + void forceRemove(const LLViewerWearable* pWearable); + void forceRemove(LLWearableType::EType wtType); + +public: + void done(); +protected: + void addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction); + void remAttachment(const LLViewerObject* pAttachObj); + void addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction); + void remWearable(const LLViewerWearable* pWearable); + + // Convenience (prevents long lines that run off the screen elsewhere) + bool isAddAttachment(const LLViewerInventoryItem* pItem) const + { + bool fFound = false; + for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); + (!fFound) && (itAddAttachments != m_addAttachments.end()); ++itAddAttachments) + { + const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second; + fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end()); + } + return fFound; + } + bool isRemAttachment(const LLViewerObject* pAttachObj) const + { + return std::find(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj) != m_remAttachments.end(); + } + bool isAddWearable(const LLViewerInventoryItem* pItem) const + { + bool fFound = false; + for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); + (!fFound) && (itAddWearables != m_addWearables.end()); ++itAddWearables) + { + const LLInventoryModel::item_array_t& wearItems = itAddWearables->second; + fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end()); + } + return fFound; + } + bool isRemWearable(const LLViewerWearable* pWearable) const + { + return std::find(m_remWearables.begin(), m_remWearables.end(), pWearable) != m_remWearables.end(); + } + + /* + * Pending attachments + */ +public: + static void updatePendingAttachments(); +protected: + void addPendingAttachment(const LLUUID& idItem, U8 idxPoint); + void remPendingAttachment(const LLUUID& idItem); + +protected: + typedef std::pair<LLWearableType::EType, LLInventoryModel::item_array_t> addwearable_pair_t; + typedef std::map<LLWearableType::EType, LLInventoryModel::item_array_t> addwearables_map_t; + addwearables_map_t m_addWearables; + typedef std::pair<S32, LLInventoryModel::item_array_t> addattachment_pair_t; + typedef std::map<S32, LLInventoryModel::item_array_t> addattachments_map_t; + addattachments_map_t m_addAttachments; + LLInventoryModel::item_array_t m_addGestures; + std::vector<LLViewerObject*> m_remAttachments; // This should match the definition of LLAgentWearables::llvo_vec_t + std::list<const LLViewerWearable*> m_remWearables; + LLInventoryModel::item_array_t m_remGestures; + + typedef std::map<LLUUID, U8> pendingattachments_map_t; + pendingattachments_map_t m_pendingAttachments; + +private: + friend class LLSingleton<RlvForceWear>; +}; + +// ============================================================================ +// RlvBehaviourNotifyObserver +// + +class RlvBehaviourNotifyHandler : public LLSingleton<RlvBehaviourNotifyHandler> +{ + LLSINGLETON(RlvBehaviourNotifyHandler); +protected: + virtual ~RlvBehaviourNotifyHandler() { if (m_ConnCommand.connected()) m_ConnCommand.disconnect(); } + +public: + void addNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter) + { + m_Notifications.insert(std::pair<LLUUID, notifyData>(idObj, notifyData(nChannel, strFilter))); + } + void removeNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter) + { + for (std::multimap<LLUUID, notifyData>::iterator itNotify = m_Notifications.lower_bound(idObj), + endNotify = m_Notifications.upper_bound(idObj); itNotify != endNotify; ++itNotify) + { + if ( (itNotify->second.nChannel == nChannel) && (itNotify->second.strFilter == strFilter) ) + { + m_Notifications.erase(itNotify); + break; + } + } + if (m_Notifications.empty()) + delete this; // Delete ourself if we have nothing to do + } + static void sendNotification(const std::string& strText, const std::string& strSuffix = LLStringUtil::null); + + /* + * Event handlers + */ +public: + static void onWear(LLWearableType::EType eType, bool fAllowed); + static void onTakeOff(LLWearableType::EType eType, bool fAllowed); + static void onAttach(const LLViewerJointAttachment* pAttachPt, bool fAllowed); + static void onDetach(const LLViewerJointAttachment* pAttachPt, bool fAllowed); + static void onReattach(const LLViewerJointAttachment* pAttachPt, bool fAllowed); +protected: + void onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal); + +protected: + struct notifyData + { + S32 nChannel; + std::string strFilter; + notifyData(S32 channel, const std::string& filter) : nChannel(channel), strFilter(filter) {} + }; + std::multimap<LLUUID, notifyData> m_Notifications; + boost::signals2::connection m_ConnCommand; +}; + +// ============================================================================ +// RlvException +// + +struct RlvException +{ +public: + LLUUID idObject; // UUID of the object that added the exception + ERlvBehaviour eBehaviour; // Behaviour the exception applies to + RlvExceptionOption varOption; // Exception data (type is dependent on eBehaviour) + + RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {} +private: + RlvException(); +}; + +// ============================================================================ +// Various helper classes/timers/functors +// + +class RlvGCTimer : public LLEventTimer +{ +public: + RlvGCTimer() : LLEventTimer(30.0) {} + virtual BOOL tick(); +}; + +// NOTE: Unused as of SL-3.7.2 +class RlvCallbackTimerOnce : public LLEventTimer +{ +public: + typedef boost::function<void ()> nullary_func_t; +public: + RlvCallbackTimerOnce(F32 nPeriod, nullary_func_t cb) : LLEventTimer(nPeriod), m_Callback(cb) {} + /*virtual*/ BOOL tick() + { + m_Callback(); + return TRUE; + } +protected: + nullary_func_t m_Callback; +}; + +// NOTE: Unused as of SL-3.7.2 +inline void rlvCallbackTimerOnce(F32 nPeriod, RlvCallbackTimerOnce::nullary_func_t cb) +{ + // Timer will automatically delete itself after the callback + new RlvCallbackTimerOnce(nPeriod, cb); +} + +// ============================================================================ +// Various helper functions +// + +ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup); +ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup); + +std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch = NULL); +std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart = NULL); + +// ============================================================================ +// Inlined class member functions +// + +inline void RlvBehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable) +{ + if (fEnable) + m_nBhvrFlags |= eBhvrFlag; + else + m_nBhvrFlags &= ~eBhvrFlag; +} + +// Checked: 2009-09-19 (RLVa-1.0.3d) +inline std::string RlvCommand::asString() const +{ + // NOTE: @clear=<param> should be represented as clear:<param> + return (m_eParamType != RLV_TYPE_CLEAR) + ? (!m_strOption.empty()) ? (std::string(getBehaviour())).append(":").append(m_strOption) : (std::string(getBehaviour())) + : (!m_strParam.empty()) ? (std::string(getBehaviour())).append(":").append(m_strParam) : (std::string(getBehaviour())); +} + +inline bool RlvCommand::operator ==(const RlvCommand& rhs) const +{ + // The specification notes that "@detach=n" is semantically identical to "@detach=add" (same for "y" and "rem" + return (getBehaviour() == rhs.getBehaviour()) && (m_strOption == rhs.m_strOption) && + ( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) ); +} + +// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d +inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem) +{ + LLAssetType::EType assetType = (pItem) ? pItem->getType() : LLAssetType::AT_NONE; + return + (LLAssetType::AT_BODYPART == assetType) || (LLAssetType::AT_CLOTHING == assetType) || + (LLAssetType::AT_OBJECT == assetType) || (LLAssetType::AT_GESTURE == assetType); +} + +// ============================================================================ + +#endif // RLV_HELPER_H diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..082cc6065b5d1eeeb2ed9b7a260bb0192915e838 --- /dev/null +++ b/indra/newview/rlvinventory.cpp @@ -0,0 +1,882 @@ +/** + * + * Copyright (c) 2009-2014, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llappearancemgr.h" +#include "llstartup.h" +#include "llviewerfoldertype.h" +#include "llviewermessage.h" + +#include "rlvinventory.h" + +#include "boost/algorithm/string.hpp" + +// ============================================================================ +// Static variable initialization +// + +const std::string RlvInventory::cstrSharedRoot = RLV_ROOT_FOLDER; + +// ============================================================================ +// Helper classes +// + +// TODO-RLVa: [RLVa-1.2.1] This class really shouldn't be calling "fetchSharedLinks" directly so find a better way +class RlvSharedInventoryFetcher : public LLInventoryFetchDescendentsObserver +{ +public: + RlvSharedInventoryFetcher(const uuid_vec_t& idFolders): LLInventoryFetchDescendentsObserver(idFolders) {} + virtual ~RlvSharedInventoryFetcher() {} + + virtual void done() + { + RLV_INFOS << "Shared folders fetch completed" << LL_ENDL; + RlvInventory::instance().m_fFetchComplete = true; + RlvInventory::instance().fetchSharedLinks(); + + gInventory.removeObserver(this); + delete this; + } +}; + +// ============================================================================ +// RlvInventory member functions +// + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +RlvInventory::RlvInventory() + : m_fFetchStarted(false), m_fFetchComplete(false) +{ +} + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +RlvInventory::~RlvInventory() +{ + if (gInventory.containsObserver(this)) + gInventory.removeObserver(this); +} + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +void RlvInventory::changed(U32 mask) +{ + const LLInventoryModel::changed_items_t& idsChanged = gInventory.getChangedIDs(); + if (std::find(idsChanged.begin(), idsChanged.end(), m_idRlvRoot) != idsChanged.end()) + { + gInventory.removeObserver(this); + + LLUUID idRlvRootPrev = m_idRlvRoot; + m_idRlvRoot.setNull(); + + if (idRlvRootPrev != getSharedRootID()) + m_OnSharedRootIDChanged(); + } +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +void RlvInventory::fetchSharedInventory() +{ + // Sanity check - don't fetch if we're already fetching, or if we don't have a shared root + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + if ( (m_fFetchStarted) || (!pRlvRoot) ) + return; + + // Grab all the folders under the shared root + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + gInventory.collectDescendents(pRlvRoot->getUUID(), folders, items, FALSE); + + // Add them to the "to fetch" list + uuid_vec_t idFolders; + idFolders.push_back(pRlvRoot->getUUID()); + for (S32 idxFolder = 0, cntFolder = folders.size(); idxFolder < cntFolder; idxFolder++) + idFolders.push_back(folders.at(idxFolder)->getUUID()); + + // Now fetch them all in one go + RlvSharedInventoryFetcher* pFetcher = new RlvSharedInventoryFetcher(idFolders); + + RLV_INFOS << "Starting fetch of " << idFolders.size() << " shared folders" << RLV_ENDL; + pFetcher->startFetch(); + m_fFetchStarted = true; + + if (pFetcher->isFinished()) + pFetcher->done(); + else + gInventory.addObserver(pFetcher); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +void RlvInventory::fetchSharedLinks() +{ + // TOFIX-RLVa: [RLVa-1.2.1] Finish adding support for AT_LINK_FOLDER + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + if (!pRlvRoot) + return; + + // Grab all the inventory links under the shared root + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; RlvIsLinkType f; + gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f, false); + + // Add them to the "to fetch" list based on link type + uuid_vec_t idFolders, idItems; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = items.at(idxItem); + switch (pItem->getActualType()) + { + case LLAssetType::AT_LINK: + idItems.push_back(pItem->getLinkedUUID()); + break; + case LLAssetType::AT_LINK_FOLDER: + idFolders.push_back(pItem->getLinkedUUID()); + break; + default: + break;; + } + } + + RLV_INFOS << "Starting link target fetch of " << idItems.size() << " items and " << idFolders.size() << " folders" << RLV_ENDL; + + // Fetch all the link item targets + LLInventoryFetchItemsObserver itemFetcher(idItems); + itemFetcher.startFetch(); + + // Fetch all the link folder targets + // TODO! +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvInventory::fetchWornItems() +{ + uuid_vec_t idItems; + + // Fetch all currently worn clothing layers and body parts + for (int type = 0; type < LLWearableType::WT_COUNT; type++) + { + // RELEASE-RLVa: [SL-2.0.0] Needs rewriting once 'LLAgentWearables::MAX_WEARABLES_PER_TYPE > 1' + const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0); + if (idItem.notNull()) + idItems.push_back(idItem); + } + + // Fetch all currently worn attachments + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if (pAttachPt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = (*itAttachObj); + if ( (pAttachObj) && (pAttachObj->getAttachmentItemID().notNull()) ) + idItems.push_back(pAttachObj->getAttachmentItemID()); + } + } + } + } + + LLInventoryFetchItemsObserver itemFetcher(idItems); + itemFetcher.startFetch(); +} + +// Checked: 2010-04-07 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h +bool RlvInventory::findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const +{ + // Sanity check - can't do anything without a shared root + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (!pRlvRoot) + return false; + + folders.clear(); + LLInventoryModel::item_array_t items; + RlvCriteriaCategoryCollector f(strCriteria); + gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f); + + return (folders.size() != 0); +} + +// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c +bool RlvInventory::getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const +{ + // Sanity check - can't do anything without a shared root + const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); + if (!pRlvRoot) + return false; + + folders.clear(); + for (uuid_vec_t::const_iterator itItem = idItems.begin(); itItem != idItems.end(); ++itItem) + { + const LLInventoryItem* pItem = gInventory.getItem(*itItem); + if ( (pItem) && (gInventory.isObjectDescendentOf(pItem->getUUID(), pRlvRoot->getUUID())) ) + { + // If the containing folder is a folded folder we need its parent + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + if (RlvInventory::instance().isFoldedFolder(pFolder, true)) + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + folders.push_back(pFolder); + } + } + + return (folders.size() != 0); +} + +// Checked: 2011-10-06 (RLVa-1.4.2a) | Modified: RLVa-1.4.2a +const LLUUID& RlvInventory::getSharedRootID() const +{ + if ( (m_idRlvRoot.isNull()) && (gInventory.isInventoryUsable()) ) + { + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(gInventory.getRootFolderID(), pFolders, pItems); + if (pFolders) + { + // NOTE: we might have multiple #RLV folders (pick the first one with sub-folders; otherwise the last one with no sub-folders) + const LLViewerInventoryCategory* pFolder; + for (S32 idxFolder = 0, cntFolder = pFolders->size(); idxFolder < cntFolder; idxFolder++) + { + if ( ((pFolder = pFolders->at(idxFolder)) != NULL) && (cstrSharedRoot == pFolder->getName()) ) + { + m_idRlvRoot = pFolder->getUUID(); + if (getDirectDescendentsFolderCount(pFolder) > 0) + break; + } + } + if ( (m_idRlvRoot.notNull()) && (!gInventory.containsObserver((RlvInventory*)this)) ) + gInventory.addObserver((RlvInventory*)this); + } + } + return m_idRlvRoot; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.1a +LLViewerInventoryCategory* RlvInventory::getSharedFolder(const LLUUID& idParent, const std::string& strFolderName, bool fMatchPartial) const +{ + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(idParent, pFolders, pItems); + if ( (!pFolders) || (strFolderName.empty()) ) + return NULL; + + // If we can't find an exact match then we'll settle for a "contains" match + LLViewerInventoryCategory* pPartial = NULL; + for (LLInventoryModel::cat_array_t::const_iterator itFolder = pFolders->begin(); itFolder != pFolders->end(); ++itFolder) + { + LLViewerInventoryCategory* pFolder = *itFolder; + const std::string& strName = pFolder->getName(); + + if (boost::iequals(strName, strFolderName)) + return pFolder; // Found an exact match, no need to keep on going + else if ( (fMatchPartial) && (!pPartial) && (RLV_FOLDER_PREFIX_HIDDEN != strName[0]) && (boost::icontains(strName, strFolderName)) ) + pPartial = pFolder; // Found a partial (non-hidden) match, but we might still find an exact one (first partial match wins) + } + + return pPartial; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-0.2.0e +LLViewerInventoryCategory* RlvInventory::getSharedFolder(const std::string& strPath, bool fMatchPartial) const +{ + // Sanity check - no shared root => no shared folder + LLViewerInventoryCategory* pRlvRoot = getSharedRoot(), *pFolder = pRlvRoot; + if (!pRlvRoot) + return NULL; + + // Walk the path (starting at the root) + boost_tokenizer tokens(strPath, boost::char_separator<char>("/", "", boost::drop_empty_tokens)); + for (boost_tokenizer::const_iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + { + pFolder = getSharedFolder(pFolder->getUUID(), *itToken, fMatchPartial); + if (!pFolder) + return NULL; // No such folder + } + + return pFolder; // If strPath was empty or just a bunch of //// then: pFolder == pRlvRoot +} + +// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-0.2.0g +std::string RlvInventory::getSharedPath(const LLViewerInventoryCategory* pFolder) const +{ + // Sanity check - no shared root or no folder => no path + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + if ( (!pRlvRoot) || (!pFolder) || (pRlvRoot->getUUID() == pFolder->getUUID()) ) + return std::string(); + + const LLUUID& idRLV = pRlvRoot->getUUID(); + const LLUUID& idRoot = gInventory.getRootFolderID(); + std::string strPath; + + // Walk up the tree until we reach the top + RLV_ASSERT(gInventory.isObjectDescendentOf(pFolder->getUUID(), pRlvRoot->getUUID())); + while (pFolder) + { + strPath = "/" + pFolder->getName() + strPath; + + const LLUUID& idParent = pFolder->getParentUUID(); + if (idRLV == idParent) // Reached the shared root, we're done + break; + else if (idRoot == idParent) // We reached the agent's inventory root (indicative of a logic error elsewhere) + return std::string(); + + pFolder = gInventory.getCategory(idParent); + } + + return strPath.erase(0, 1); +} + +// Checked: 2011-10-06 (RLVa-1.4.2a) | Added: RLVa-1.4.2a +S32 RlvInventory::getDirectDescendentsFolderCount(const LLInventoryCategory* pFolder) +{ + LLInventoryModel::cat_array_t* pFolders = NULL; LLInventoryModel::item_array_t* pItems = NULL; + if (pFolder) + gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); + return (pFolders) ? pFolders->size() : 0; +} + +// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d +S32 RlvInventory::getDirectDescendentsItemCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType) +{ + S32 cntType = 0; + if (pFolder) + { + LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems; + gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems); + + if (pItems) + { + for (S32 idxItem = 0, cntItem = pItems->size(); idxItem < cntItem; idxItem++) + if (pItems->at(idxItem)->getType() == filterType) + cntType++; + } + } + return cntType; +} + +// Checked: 2012-11-28 (RLVa-1.4.8) +bool RlvInventory::isGiveToRLVOffer(const LLOfferInfo& offerInfo) +{ + if ( (!RlvSettings::getForbidGiveToRLV()) && (RlvInventory::instance().getSharedRoot()) ) + { + if (offerInfo.mFromObject) + { + return + (IM_TASK_INVENTORY_OFFERED == offerInfo.mIM) && + (LLAssetType::AT_CATEGORY == offerInfo.mType) && (offerInfo.mDesc.find(RLV_PUTINV_PREFIX) == 1); + } + else + { + return + (IM_INVENTORY_OFFERED == offerInfo.mIM) && + (LLAssetType::AT_CATEGORY == offerInfo.mType) && (offerInfo.mDesc.find(RLV_PUTINV_PREFIX) == 0); + } + } + return false; +} + +// ============================================================================ +// RlvRenameOnWearObserver member functions +// + +// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvRenameOnWearObserver::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvRenameOnWearObserver::doneIdle, this)); +} + +// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +void RlvRenameOnWearObserver::doneIdle() +{ + const LLViewerInventoryCategory* pRlvRoot = NULL; + if ( (RlvSettings::getEnableSharedWear()) || (!RlvSettings::getSharedInvAutoRename()) || (LLStartUp::getStartupState() < STATE_STARTED) || + (!isAgentAvatarValid()) || ((pRlvRoot = RlvInventory::instance().getSharedRoot()) == NULL) ) + { + delete this; + return; + } + + const LLViewerJointAttachment* pAttachPt = NULL; S32 idxAttachPt = 0; + RLV_ASSERT(mComplete.size() > 0); // Catch instances where we forgot to call startFetch() + for (uuid_vec_t::const_iterator itItem = mComplete.begin(); itItem != mComplete.end(); ++itItem) + { + const LLUUID& idAttachItem = *itItem; + + // If the item resides under #RLV we'll rename it directly; otherwise settle for "renaming" all of its links residing under #RLV + LLInventoryModel::item_array_t items; + if (gInventory.isObjectDescendentOf(idAttachItem, pRlvRoot->getUUID())) + items.push_back(gInventory.getItem(idAttachItem)); +// // LL kind of messed up the collectLinkedItems (now collectLinksTo) function but I'm not sure if this use-case if worth fixing it for +// else +// items = gInventory.collectLinkedItems(idAttachItem, pRlvRoot->getUUID()); + if (items.empty()) + continue; + + if ( ((pAttachPt = gAgentAvatarp->getWornAttachmentPoint(idAttachItem)) == NULL) || + ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt)) == 0) ) + { + RLV_ASSERT(false); + continue; + } + + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.at(idxItem); + if (!pItem) + continue; + + S32 idxAttachPtItem = RlvAttachPtLookup::getAttachPointIndex(pItem); + if ( (idxAttachPt == idxAttachPtItem) || (idxAttachPtItem) ) + continue; + + std::string strAttachPt = pAttachPt->getName(); + LLStringUtil::toLower(strAttachPt); + + // If we can modify the item then we rename it directly, otherwise we create a new folder and move it + if (pItem->getPermissions().allowModifyBy(gAgent.getID())) + { + std::string strName = pItem->getName(); + LLStringUtil::truncate(strName, DB_INV_ITEM_NAME_STR_LEN - strAttachPt.length() - 3); + + strName += " (" + strAttachPt + ")"; + + pItem->rename(strName); + pItem->updateServer(FALSE); + gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getUUID()); + } + else + { + // Don't do anything if the item is a direct descendant of the shared root, or a folded folder + LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID()); + if ( (pFolder) && (pFolder->getUUID() != pRlvRoot->getUUID()) && (!RlvInventory::isFoldedFolder(pFolder, false)) ) + { + std::string strFolderName = ".(" + strAttachPt + ")"; + + // Rename the item's parent folder if it's called "New Folder", isn't directly under #RLV and contains exactly 1 object + if ( (LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE) == pFolder->getName()) && + (pFolder->getParentUUID() != pRlvRoot->getUUID()) && + (1 == RlvInventory::getDirectDescendentsItemCount(pFolder, LLAssetType::AT_OBJECT)) ) + { + pFolder->rename(strFolderName); + pFolder->updateServer(FALSE); + gInventory.addChangedMask(LLInventoryObserver::LABEL, pFolder->getUUID()); + } + else + { + // "No modify" item with a non-renameable parent: create a new folder named and move the item into it + inventory_func_type f = boost::bind(RlvRenameOnWearObserver::onCategoryCreate, _1, pItem->getUUID()); + LLUUID idFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName, f); + if (idFolder.notNull()) + { + // Not using the new 'CreateInventoryCategory' cap so manually invoke the callback + RlvRenameOnWearObserver::onCategoryCreate(idFolder, pItem->getUUID()); + } + } + } + } + } + } + gInventory.notifyObservers(); + + delete this; +} + +// Checked: 2012-03-22 (RLVa-1.4.6) | Added: RLVa-1.4.6 +void RlvRenameOnWearObserver::onCategoryCreate(const LLUUID& idFolder, const LLUUID idItem) +{ + if ( (idFolder.notNull()) && (idItem.notNull()) ) + move_inventory_item(gAgent.getID(), gAgent.getSessionID(), idItem, idFolder, std::string(), NULL); +} + +// ============================================================================ +// "Give to #RLV" helper classes +// + +// Checked: 2014-01-07 (RLVa-1.4.10) +bool RlvGiveToRLVOffer::createDestinationFolder(const std::string& strPath) +{ + // NOTE: derived classes will delete the instance in their onDestinationCreated override, so don't do anything after triggering the callback + + m_DestPath.clear(); + if (0 == strPath.find(RLV_PUTINV_PREFIX)) + { + boost::split(m_DestPath, strPath, boost::is_any_of(std::string(RLV_PUTINV_SEPARATOR))); + } + + if ( (m_DestPath.size() >= 2) && (m_DestPath.size() <= RLV_PUTINV_MAXDEPTH) ) + { + const std::string strFolder = m_DestPath.front(); + if (RLV_ROOT_FOLDER == strFolder) + { + m_DestPath.pop_front(); + + const LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID(); + if (idRlvRoot.notNull()) + { + onCategoryCreateCallback(idRlvRoot, this); + } + else + { + inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, this); + const LLUUID idTemp = gInventory.createNewCategory(gInventory.getRootFolderID(), LLFolderType::FT_NONE, RLV_ROOT_FOLDER, f); + if (idTemp.notNull()) + onCategoryCreateCallback(idTemp, this); + } + return true; + } + } + m_DestPath.clear(); + return false; +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVOffer::onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOffer* pInstance) +{ + if (idFolder.isNull()) + { + // Problem encountered, abort move + pInstance->onDestinationCreated(LLUUID::null, LLStringUtil::null); + return; + } + + while (pInstance->m_DestPath.size() > 1) + { + std::string strFolder = pInstance->m_DestPath.front(); + pInstance->m_DestPath.pop_front(); + + const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(idFolder, strFolder, false); + if (pFolder) + { + idFolder = pFolder->getUUID(); + } + else + { + LLInventoryObject::correctInventoryName(strFolder); + inventory_func_type f = boost::bind(RlvGiveToRLVOffer::onCategoryCreateCallback, _1, pInstance); + const LLUUID idTemp = gInventory.createNewCategory(idFolder, LLFolderType::FT_NONE, strFolder, f); + if (idTemp.notNull()) + onCategoryCreateCallback(idTemp, pInstance); + return; + } + } + + // Destination folder should exist at this point (we'll be deallocated when the function returns) + pInstance->onDestinationCreated(idFolder, pInstance->m_DestPath.front()); +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVOffer::moveAndRename(const LLUUID& idFolder, const LLUUID& idDestination, const std::string& strName) +{ + const LLViewerInventoryCategory* pDest = gInventory.getCategory(idDestination); + const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder); + if ( (pDest) && (pFolder) ) + { + LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder); + if (pDest->getUUID() != pFolder->getParentUUID()) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate updOldParent(pFolder->getParentUUID(), -1); + update.push_back(updOldParent); + LLInventoryModel::LLCategoryUpdate updNewParent(pDest->getUUID(), 1); + update.push_back(updNewParent); + gInventory.accountForUpdate(update); + + pNewFolder->setParent(pDest->getUUID()); + pNewFolder->updateParentOnServer(FALSE); + } + + pNewFolder->rename(strName); + pNewFolder->updateServer(FALSE); + gInventory.updateCategory(pNewFolder); + + gInventory.notifyObservers(); + } +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVTaskOffer::changed(U32 mask) +{ + if (mask & LLInventoryObserver::ADD) + { + LLMessageSystem* pMsg = gMessageSystem; + if ( (pMsg->getMessageName()) && (0 == strcmp(pMsg->getMessageName(), "BulkUpdateInventory")) ) + { + LLUUID idTransaction; + pMsg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, idTransaction); + if (m_idTransaction == idTransaction) + { + LLUUID idInvObject; + for (S32 idxBlock = 0, cntBlock = pMsg->getNumberOfBlocksFast(_PREHASH_FolderData); idxBlock < cntBlock; idxBlock++) + { + pMsg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, idInvObject, idxBlock); + if ( (idInvObject.notNull()) && (std::find(m_Folders.begin(), m_Folders.end(), idInvObject) == m_Folders.end()) ) + m_Folders.push_back(idInvObject); + } + + done(); + } + } + } +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVTaskOffer::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvGiveToRLVTaskOffer::doneIdle, this)); +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVTaskOffer::doneIdle() +{ + const LLViewerInventoryCategory* pFolder = (m_Folders.size()) ? gInventory.getCategory(m_Folders.front()) : NULL; + if ( (!pFolder) || (!createDestinationFolder(pFolder->getName())) ) + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVTaskOffer::onDestinationCreated(const LLUUID& idFolder, const std::string& strName) +{ + const LLViewerInventoryCategory* pTarget = (idFolder.notNull()) ? gInventory.getCategory(idFolder) : NULL; + if (pTarget) + { + const LLUUID& idOfferedFolder = m_Folders.front(); + moveAndRename(idOfferedFolder, idFolder, strName); + RlvBehaviourNotifyHandler::sendNotification("accepted_in_rlv inv_offer " + RlvInventory::instance().getSharedPath(idOfferedFolder)); + } + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVAgentOffer::done() +{ + gInventory.removeObserver(this); + + // We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers() + doOnIdleOneTime(boost::bind(&RlvGiveToRLVAgentOffer::doneIdle, this)); +} + +// Checked: 2014-01-07 (RLVa-1.4.10) +void RlvGiveToRLVAgentOffer::doneIdle() +{ + const LLViewerInventoryCategory* pFolder = (mComplete.size()) ? gInventory.getCategory(mComplete.front()) : NULL; + if ( (!pFolder) || (!createDestinationFolder(pFolder->getName())) ) + delete this; +} + +// Checked: 2010-04-18 (RLVa-1.2.0) +void RlvGiveToRLVAgentOffer::onDestinationCreated(const LLUUID& idFolder, const std::string& strName) +{ + if ( (idFolder.notNull()) && (mComplete.size()) ) + moveAndRename(mComplete[0], idFolder, strName); + delete this; +} + +// ============================================================================ +// RlvWearableItemCollector +// + +// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvWearableItemCollector::RlvWearableItemCollector(const LLInventoryCategory* pFolder, RlvForceWear::EWearAction eAction, RlvForceWear::EWearFlags eFlags) + : m_idFolder(pFolder->getUUID()), m_eWearAction(eAction), m_eWearFlags(eFlags), + m_strWearAddPrefix(RlvSettings::getWearAddPrefix()), m_strWearReplacePrefix(RlvSettings::getWearReplacePrefix()) +{ + m_Wearable.push_back(m_idFolder); + + // Wear prefixes can't/shouldn't start with '.' + if ( (m_strWearAddPrefix.length() > 1) && (RLV_FOLDER_PREFIX_HIDDEN == m_strWearAddPrefix[0]) ) + m_strWearAddPrefix.clear(); + if ( (m_strWearReplacePrefix.length() > 1) && (RLV_FOLDER_PREFIX_HIDDEN == m_strWearReplacePrefix[0]) ) + m_strWearReplacePrefix.clear(); + + // If there's a prefix on the "root" folder then it will override what we were passed in the constructor + m_eWearAction = getWearActionNormal(pFolder); + m_WearActionMap.insert(std::pair<LLUUID, RlvForceWear::EWearAction>(m_idFolder, m_eWearAction)); +} + +// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvForceWear::EWearAction RlvWearableItemCollector::getWearActionNormal(const LLInventoryCategory* pFolder) +{ + RLV_ASSERT_DBG(!RlvInventory::isFoldedFolder(pFolder, false)); + if ( (RlvForceWear::ACTION_WEAR_REPLACE == m_eWearAction) && (!m_strWearAddPrefix.empty()) && + (boost::algorithm::starts_with(pFolder->getName(), m_strWearAddPrefix))) + { + return RlvForceWear::ACTION_WEAR_ADD; + } + else if ( (RlvForceWear::ACTION_WEAR_ADD == m_eWearAction) && (!m_strWearReplacePrefix.empty()) && + (boost::algorithm::starts_with(pFolder->getName(), m_strWearReplacePrefix)) ) + { + return RlvForceWear::ACTION_WEAR_REPLACE; + } + return (pFolder->getUUID() != m_idFolder) ? getWearAction(pFolder->getParentUUID()) : m_eWearAction; +} + +// Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0e +const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) const +{ + std::map<LLUUID, LLUUID>::const_iterator itFolder = m_FoldingMap.end(), itCur = m_FoldingMap.find(idFolder); + while (itCur != m_FoldingMap.end()) + { + itFolder = itCur; + itCur = m_FoldingMap.find(itFolder->second); + } + return (m_FoldingMap.end() == itFolder) ? idFolder : itFolder->second; +} + +// Checked: 2010-09-25 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +RlvForceWear::EWearAction RlvWearableItemCollector::getWearAction(const LLUUID& idFolder) const +{ + LLUUID idCurFolder(idFolder); std::map<LLUUID, RlvForceWear::EWearAction>::const_iterator itCurFolder; + while ((itCurFolder = m_WearActionMap.find(idCurFolder)) == m_WearActionMap.end()) + { + const LLViewerInventoryCategory* pFolder = gInventory.getCategory(idCurFolder); + if ((!pFolder) || (gInventory.getRootFolderID() == pFolder->getParentUUID())) + break; + idCurFolder = pFolder->getParentUUID(); + } + return (itCurFolder != m_WearActionMap.end()) ? itCurFolder->second : m_eWearAction; +} + +// Checked: 2010-09-30 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d +bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder) +{ + // We treat folder links differently since they won't exist in the wearable folder list yet and their ancestry isn't relevant + bool fLinkedFolder = isLinkedFolder(pFolder->getUUID()); + if ( (!fLinkedFolder) && (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), pFolder->getParentUUID())) ) + return false; // Not a linked folder or the child of a wearable folder + + const std::string& strFolder = pFolder->getName(); + if (strFolder.empty()) // Shouldn't happen but does... naughty Lindens + return false; + + bool fAttach = RlvForceWear::isWearAction(m_eWearAction); + bool fMatchAll = (!fLinkedFolder) && (m_eWearFlags & RlvForceWear::FLAG_MATCHALL); + + if ( (!fLinkedFolder) && (RlvInventory::isFoldedFolder(pFolder, false)) ) // Check for folder that should get folded under its parent + { + if ( (!fAttach) || (1 == RlvInventory::getDirectDescendentsItemCount(pFolder, LLAssetType::AT_OBJECT)) ) + { // When attaching there should only be 1 attachment in it + m_Folded.push_front(pFolder->getUUID()); + m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), pFolder->getParentUUID())); + } + } + else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && // Collect from any non-hidden child folder for *all + ( (fMatchAll) || (fLinkedFolder) ) && // ... and collect from linked folders + (!isLinkedFolder(pFolder->getParentUUID())) ) // ... but never from non-folded linked folder descendents + { + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + if ( (!RlvSettings::getEnableComposites()) || // ... if we're not checking composite folders + (!gRlvHandler.isCompositeFolder(pFolder)) || // ... or if it's not a composite folder + ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... or if we're attaching and can attach it OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) // ... or if we're detaching and can detach it + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + { + m_Wearable.push_front(pFolder->getUUID()); + m_WearActionMap.insert(std::pair<LLUUID, RlvForceWear::EWearAction>(pFolder->getUUID(), getWearActionNormal(pFolder))); + } + return (!fLinkedFolder) && (pFolder->getParentUUID() == m_idFolder); // Convenience for @getinvworn + } + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + else if ( (RlvSettings::getEnableComposites()) && + (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) && // Hidden folder that's a... + (gRlvHandler.isCompositeFolder(pFolder)) && // ... composite folder which we... + ( ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) || // ... are attaching and can attach OR + (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) ) // ... are detaching and can detach + { + m_Wearable.push_front(pFolder->getUUID()); + m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent)); + } + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + + return false; +} + +// Checked: 2010-09-30 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d +bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem) +{ + bool fAttach = RlvForceWear::isWearAction(m_eWearAction); + + if ( (!fAttach) && (!RlvForceWear::isStrippable(pItem)) ) // Don't process "nostrip" items on detach + return false; + + const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false; + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + if (!fAttach) + break; // Don't process body parts on detach + case LLAssetType::AT_CLOTHING: + fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || + ( (fAttach) && (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) && + (RlvForceWear::isStrippable(pItem)) ) ); + break; + case LLAssetType::AT_OBJECT: + fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || + (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) ) && + ( (!fAttach) || (RlvAttachPtLookup::hasAttachPointName(pItem)) || (RlvSettings::getEnableSharedWear()) ); + break; + case LLAssetType::AT_GESTURE: + fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)); + break; + case LLAssetType::AT_CATEGORY: + if (LLAssetType::AT_LINK_FOLDER == pItem->getActualType()) + { + const LLUUID& idLinkedFolder = pItem->getLinkedUUID(); + LLViewerInventoryCategory* pLinkedFolder = gInventory.getCategory(idLinkedFolder); + // Link can't point to an outfit folder, or start a second level of indirection, or have the base folder as an ancestor + if ( (pLinkedFolder) && (LLFolderType::FT_OUTFIT != pLinkedFolder->getPreferredType()) && + (gInventory.isObjectDescendentOf(pItem->getUUID(), m_idFolder)) && + (!gInventory.isObjectDescendentOf(idLinkedFolder, m_idFolder)) ) + { + // Fold the contents of the linked folder under the folder the link is a child of + m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(idLinkedFolder, pItem->getParentUUID())); + m_Linked.push_front(idLinkedFolder); + } + } + break; + default: + break; + } + return fRet; +} + +// Checked: 2010-03-20 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d +bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) +{ + // NOTE: this is used for more than was originally intended so only modify if you're sure it won't break something obscure + return (pFolder) ? onCollectFolder(pFolder) : ( (pItem) ? onCollectItem(pItem) : false ); +} + +// ============================================================================ +// General purpose inventory helper classes +// + +// Checked: 2013-10-12 (RLVa-1.4.9) +bool RlvFindAttachmentsOnPoint::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) +{ +#ifndef RLV_DEPRECATE_ATTACHPTNAMING + // First check if the item is attached to the attachment point; fall back to the item name otherwise + return (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && + ( ((m_pAttachPt) && (m_pAttachPt->getAttachedObject(pItem->getLinkedUUID()))) || (RlvAttachPtLookup::getAttachPoint(pItem) == m_pAttachPt) ); +#else + return (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (m_pAttachPt) && (m_pAttachPt->getAttachedObject(pItem->getLinkedUUID())); +#endif // RLV_DEPRECATE_LEGACY_ATTACHPT +} + +// ============================================================================ diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h new file mode 100644 index 0000000000000000000000000000000000000000..1279dff2f85bdbb670050ac848df3066ee773cec --- /dev/null +++ b/indra/newview/rlvinventory.h @@ -0,0 +1,344 @@ +/** + * + * Copyright (c) 2009-2014, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_INVENTORY_H +#define RLV_INVENTORY_H + +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "llsingleton.h" + +#include "rlvhelper.h" +#include "rlvlocks.h" + +// ============================================================================ +// Forward declarations +// + +class LLOfferInfo; + +// ============================================================================ +// RlvInventory class declaration +// + +class RlvInventory : public LLSingleton<RlvInventory>, public LLInventoryObserver +{ + LLSINGLETON(RlvInventory); +public: + ~RlvInventory(); + + // LLInventoryObserver override + /*virtual*/ void changed(U32 mask); + + /* + * #RLV Shared inventory + */ +public: + typedef boost::signals2::signal<void (void)> callback_signal_t; + void addSharedRootIDChangedCallback(const callback_signal_t::slot_type& cb) { m_OnSharedRootIDChanged.connect(cb); } + // Find all folders that match a supplied criteria (clears the output array) + bool findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const; + // Gets the shared path for any shared items present in idItems (clears the output array) + bool getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const; + // Returns a pointer to the shared root folder (if there is one) + LLViewerInventoryCategory* getSharedRoot() const; + const LLUUID& getSharedRootID() const; + // Returns a subfolder of idParent that starts with strFolderName (exact match > partial match) + LLViewerInventoryCategory* getSharedFolder(const LLUUID& idParent, const std::string& strFolderName, bool fMatchPartial = true) const; + // Looks up a folder from a path (relative to the shared root) + LLViewerInventoryCategory* getSharedFolder(const std::string& strPath, bool fMatchPartial = true) const; + // Returns the path of the supplied folder (relative to the shared root) + std::string getSharedPath(const LLViewerInventoryCategory* pFolder) const; + std::string getSharedPath(const LLUUID& idFolder) const; + // Returns TRUE if the supplied folder is a descendent of the #RLV folder + bool isSharedFolder(const LLUUID& idFolder); + // Returns TRUE if the inventory offer is a "give to #RLV" offer + bool isGiveToRLVOffer(const LLOfferInfo& offerInfo); + + /* + * Inventory fetching + */ +public: + void fetchSharedInventory(); + void fetchWornItems(); +protected: + void fetchSharedLinks(); + + /* + * General purpose helper functions + */ +public: + // Returns the number of sub-folders of the specified folder + static S32 getDirectDescendentsFolderCount(const LLInventoryCategory* pFolder); + // Returns the number of direct descendents of the specified folder that have the specified type asset type + static S32 getDirectDescendentsItemCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType); + // Returns the folder the items of the specified folder should folded into (can be the folder itself) + static const LLUUID& getFoldedParent(const LLUUID& idFolder, bool fCheckComposite); + // A "folded folder" is a folder whose items logically belong to the grandparent rather than the parent + static bool isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite); + + /* + * Member variables + */ +protected: + bool m_fFetchStarted; // TRUE if we fired off an inventory fetch + bool m_fFetchComplete; // TRUE if everything was fetched + mutable LLUUID m_idRlvRoot; + callback_signal_t m_OnSharedRootIDChanged; + +private: + static const std::string cstrSharedRoot; + friend class RlvSharedInventoryFetcher; + friend class LLSingleton<RlvInventory>; +}; + +// ============================================================================ +// RlvRenameOnWearObserver - Handles "auto-rename-on-wear" for (linked) items living under #RLV +// + +class RlvRenameOnWearObserver : public LLInventoryFetchItemsObserver +{ +public: + RlvRenameOnWearObserver(const LLUUID& idItem) : LLInventoryFetchItemsObserver(idItem) {} + virtual ~RlvRenameOnWearObserver() {} + virtual void done(); +protected: + void doneIdle(); + static void onCategoryCreate(const LLUUID& idFolder, const LLUUID idItem); +}; + +// ============================================================================ +// "Give to #RLV" helper classes +// + +class RlvGiveToRLVOffer +{ +protected: + RlvGiveToRLVOffer() {} + virtual ~RlvGiveToRLVOffer() {} +protected: + bool createDestinationFolder(const std::string& strPath); + virtual void onDestinationCreated(const LLUUID& idFolder, const std::string& strName) = 0; + void moveAndRename(const LLUUID& idFolder, const LLUUID& idDestination, const std::string& strName); +private: + static void onCategoryCreateCallback(LLUUID idFolder, RlvGiveToRLVOffer* pInstance); + +private: + std::list<std::string> m_DestPath; +}; + +// [See LLInventoryTransactionObserver which says it's not entirely complete?] +// NOTE: the offer may span mulitple BulkUpdateInventory messages so if we're no longer around then (ie due to "delete this") then +// we'll miss those; in this specific case we only care about the *folder* though and that will be in the very first message +class RlvGiveToRLVTaskOffer : public LLInventoryObserver, RlvGiveToRLVOffer +{ +public: + RlvGiveToRLVTaskOffer(const LLUUID& idTransaction) : RlvGiveToRLVOffer(), m_idTransaction(idTransaction) {} + /*virtual*/ void changed(U32 mask); +protected: + /*virtual*/ void done(); + void doneIdle(); + /*virtual*/ void onDestinationCreated(const LLUUID& idFolder, const std::string& strName); + +protected: + typedef std::vector<LLUUID> folder_ref_t; + folder_ref_t m_Folders; + LLUUID m_idTransaction; +}; + +class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver, RlvGiveToRLVOffer +{ +public: + RlvGiveToRLVAgentOffer(const LLUUID& idFolder) : RlvGiveToRLVOffer(), LLInventoryFetchDescendentsObserver(idFolder) {} + /*virtual*/ ~RlvGiveToRLVAgentOffer() {} +public: + /*virtual*/ void done(); +protected: + void doneIdle(); + /*virtual*/ void onDestinationCreated(const LLUUID& idFolder, const std::string& strName); +}; + +// ============================================================================ +// RlvCriteriaCategoryCollector - Criteria based folder matching filter used by @findfolder and @findfolders +// + +class RlvCriteriaCategoryCollector : public LLInventoryCollectFunctor +{ +public: + RlvCriteriaCategoryCollector(const std::string& strCriteria) + { + std::string::size_type idxIt, idxLast = 0; + while (idxLast < strCriteria.length()) + { + idxIt = strCriteria.find("&&", idxLast); + if (std::string::npos == idxIt) + idxIt = strCriteria.length(); + if (idxIt != idxLast) + m_Criteria.push_back(strCriteria.substr(idxLast, idxIt - idxLast)); + idxLast = idxIt + 2; + } + } + virtual ~RlvCriteriaCategoryCollector() {} + + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) + { + if ( (!pFolder) || (m_Criteria.empty()) ) // We're only interested in matching folders, we don't care about items + return false; // (if there are no criteria then we don't want to return a match) + + std::string strFolderName = pFolder->getName(); + LLStringUtil::toLower(strFolderName); + + // NOTE: hidden or "give to #RLV" folders can never be a match + if ( (strFolderName.empty()) || + (RLV_FOLDER_PREFIX_HIDDEN == strFolderName[0]) || (RLV_FOLDER_PREFIX_PUTINV == strFolderName[0]) || + (std::string::npos != strFolderName.find_first_of(RLV_FOLDER_INVALID_CHARS)) ) + { + return false; + } + + for (std::list<std::string>::const_iterator itCrit = m_Criteria.begin(); itCrit != m_Criteria.end(); ++itCrit) + if (std::string::npos == strFolderName.find(*itCrit)) + return false; + return true; + } + +protected: + std::list<std::string> m_Criteria; +}; + +// ============================================================================ +// RlvWearableItemCollector - Inventory item filter used by attach/detach/attachall/detachall/getinvworn +// + +class RlvWearableItemCollector : public LLInventoryCollectFunctor +{ +public: + RlvWearableItemCollector(const LLInventoryCategory* pFolder, RlvForceWear::EWearAction eAction, RlvForceWear::EWearFlags eFlags); + virtual ~RlvWearableItemCollector() {} + + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem); + + const LLUUID& getFoldedParent(const LLUUID& idFolder) const; + RlvForceWear::EWearAction getWearAction(const LLUUID& idFolder) const; + RlvForceWear::EWearAction getWearActionNormal(const LLInventoryCategory* pFolder); + RlvForceWear::EWearAction getWearActionFolded(const LLInventoryCategory* pFolder); + bool isLinkedFolder(const LLUUID& idFolder); +protected: + const LLUUID m_idFolder; + RlvForceWear::EWearAction m_eWearAction; + RlvForceWear::EWearFlags m_eWearFlags; + + bool onCollectFolder(const LLInventoryCategory* pFolder); + bool onCollectItem(const LLInventoryItem* pItem); + + std::list<LLUUID> m_Folded; + std::list<LLUUID> m_Linked; + std::list<LLUUID> m_Wearable; + std::map<LLUUID, LLUUID> m_FoldingMap; + std::map<LLUUID, RlvForceWear::EWearAction> m_WearActionMap; + + std::string m_strWearAddPrefix; + std::string m_strWearReplacePrefix; +}; + +// ============================================================================ +// General purpose inventory helper classes +// + +class RlvIsLinkType : public LLInventoryCollectFunctor +{ +public: + RlvIsLinkType() {} + /*virtual*/ ~RlvIsLinkType() {} + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { return (pItem) && (pItem->getIsLinkType()); } +}; + +// If the attachment item is linked in COF but isn't worn (or just detached) the function will return inconsistent information +class RlvFindAttachmentsOnPoint : public LLInventoryCollectFunctor +{ +public: + RlvFindAttachmentsOnPoint(const LLViewerJointAttachment* pAttachPt) : m_pAttachPt(pAttachPt) {} + /*virtual*/ ~RlvFindAttachmentsOnPoint() {} + virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem); +protected: + const LLViewerJointAttachment* m_pAttachPt; +}; + +// ============================================================================ +// RlvInventory inlined member functions +// + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +inline LLViewerInventoryCategory* RlvInventory::getSharedRoot() const +{ + const LLUUID& idRlvRoot = getSharedRootID(); + return (idRlvRoot.notNull()) ? gInventory.getCategory(idRlvRoot) : NULL; +} + +// Checked: 2011-11-26 (RLVa-1.5.4a) | Added: RLVa-1.5.4a +inline const LLUUID& RlvInventory::getFoldedParent(const LLUUID& idFolder, bool fCheckComposite) +{ + LLViewerInventoryCategory* pFolder = gInventory.getCategory(idFolder); + while ((pFolder) && (isFoldedFolder(pFolder, fCheckComposite))) + pFolder = gInventory.getCategory(pFolder->getParentUUID()); + return (pFolder) ? pFolder->getUUID() : LLUUID::null; +} + +// Checked: 2011-11-26 (RLVa-1.5.4a) | Added: RLVa-1.5.4a +inline std::string RlvInventory::getSharedPath(const LLUUID& idFolder) const +{ + return getSharedPath(gInventory.getCategory(idFolder)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline bool RlvInventory::isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite) +{ + return + // If legacy naming isn't enabled we can return early if the folder name doesn't start with a '.' (= the most common case) + (pFolder) && ( (RlvSettings::getEnableLegacyNaming()) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) && + ( + // .(<attachpt>) type folder + (0 != RlvAttachPtLookup::getAttachPointIndex(pFolder)) + // .(nostrip) folder + || ( (pFolder) && (".(" RLV_FOLDER_FLAG_NOSTRIP ")" == pFolder->getName()) ) + // Composite folder (if composite folders are enabled and we're asked to look for them) + #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS + || ( (fCheckComposite) && (RlvSettings::getEnableComposites()) && + (pFolder) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) && (isCompositeFolder(pFolder)) ) + #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS + ); +} + +// Checked: 2010-08-29 (RLVa-1.2.0c) | Added: RLVa-1.2.0c +inline bool RlvInventory::isSharedFolder(const LLUUID& idFolder) +{ + const LLViewerInventoryCategory* pRlvRoot = getSharedRoot(); + return (pRlvRoot) ? (pRlvRoot->getUUID() != idFolder) && (gInventory.isObjectDescendentOf(idFolder, pRlvRoot->getUUID())) : false; +} + +// ============================================================================ +// RlvWearableItemCollector inlined member functions +// + +// Checked: 2010-09-30 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +inline bool RlvWearableItemCollector::isLinkedFolder(const LLUUID& idFolder) +{ + return (!m_Linked.empty()) && (m_Linked.end() != std::find(m_Linked.begin(), m_Linked.end(), idFolder)); +} + +// ============================================================================ + +#endif // RLV_INVENTORY_H diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp new file mode 100644 index 0000000000000000000000000000000000000000..746338685385f4b0b6f776992734ca0da03c1b7a --- /dev/null +++ b/indra/newview/rlvlocks.cpp @@ -0,0 +1,1307 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llappearancemgr.h" +#include "llattachmentsmgr.h" +#include "lloutfitobserver.h" +#include "llviewerobjectlist.h" +#include "llviewermenu.h" +#include "pipeline.h" + +#include "rlvlocks.h" +#include "rlvhelper.h" +#include "rlvinventory.h" + + +// ============================================================================ +// RlvAttachPtLookup member functions +// + +std::map<std::string, S32> RlvAttachPtLookup::m_AttachPtLookupMap; + +// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachPtLookup::initLookupTable() +{ + static bool fInitialized = false; + if (!fInitialized) + { + if ( (gAgentAvatarp) && (gAgentAvatarp->mAttachmentPoints.size() > 0) ) + { + std::string strAttachPtName; + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + const LLViewerJointAttachment* pAttachPt = itAttach->second; + if (pAttachPt) + { + strAttachPtName = pAttachPt->getName(); + LLStringUtil::toLower(strAttachPtName); + m_AttachPtLookupMap.insert(std::pair<std::string, S32>(strAttachPtName, itAttach->first)); + + // HACK: the RLV API randomly renames "Avatar Center" to "Root" so make sure we add it (but keep the official name) + if ("avatar center" == strAttachPtName) + { + m_AttachPtLookupMap.insert(std::pair<std::string, S32>("root", itAttach->first)); + } + } + } + fInitialized = true; + } + } +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-0.2.2a +S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerJointAttachment* pAttachPt) +{ + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); + itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach) + { + if (itAttach->second == pAttachPt) + return itAttach->first; + } + } + return 0; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b +S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryCategory* pFolder) +{ + if (!pFolder) + return 0; + + // RLVa-1.0.1 added support for legacy matching (See http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/) + if (RlvSettings::getEnableLegacyNaming()) + return getAttachPointIndexLegacy(pFolder); + + // Otherwise the only valid way to specify an attachment point in a folder name is: ^\.\(\s+attachpt\s+\) + std::string::size_type idxMatch; + std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch); + LLStringUtil::trim(strAttachPt); + + return ( (1 == idxMatch) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) ? getAttachPointIndex(strAttachPt) : 0; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks /*=true*/) +{ + // Sanity check - if it's not an object then it can't have an attachment point + if ( (!pItem) || (LLAssetType::AT_OBJECT != pItem->getType()) ) + return 0; + + // If the item is an inventory link then we first examine its target before examining the link itself + if ( (LLAssetType::AT_LINK == pItem->getActualType()) && (fFollowLinks) ) + { + S32 idxAttachPt = getAttachPointIndex(gInventory.getItem(pItem->getLinkedUUID()), false); + if (idxAttachPt) + return idxAttachPt; + } + + // The attachment point should be placed at the end of the item's name, surrounded by parenthesis + // (if there is no such text then strAttachPt will be an empty string which is fine since it means we'll look at the item's parent) + // (if the item is an inventory link then we only look at its containing folder and never examine its name) + std::string strAttachPt = + (LLAssetType::AT_LINK != pItem->getActualType()) ? rlvGetLastParenthesisedText(pItem->getName()) : LLStringUtil::null; + LLStringUtil::trim(strAttachPt); + + // If the item is modify : we look at the item's name first and only then at the containing folder + // If the item is no modify: we look at the containing folder's name first and only then at the item itself + S32 idxAttachPt = 0; + if (pItem->getPermissions().allowModifyBy(gAgent.getID())) + { + idxAttachPt = (!strAttachPt.empty()) ? getAttachPointIndex(strAttachPt) : 0; + if (!idxAttachPt) + idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID())); + } + else + { + idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID())); + if ( (!idxAttachPt) && (!strAttachPt.empty()) ) + idxAttachPt = getAttachPointIndex(strAttachPt); + } + return idxAttachPt; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.0.1b +S32 RlvAttachPtLookup::getAttachPointIndexLegacy(const LLInventoryCategory* pFolder) +{ + // Hopefully some day this can just be deprecated (see http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/) + if ( (!pFolder) || (pFolder->getName().empty()) ) + return 0; + + // Check for a (...) block *somewhere* in the name + std::string::size_type idxMatch; + std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch); + if (!strAttachPt.empty()) + { + // Could be "(attachpt)", ".(attachpt)" or "Folder name (attachpt)" + if ( (0 != idxMatch) && ((1 != idxMatch) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) && // No '(' or '.(' start + (idxMatch + strAttachPt.length() + 1 != pFolder->getName().length()) ) // or there's extra text + { + // It's definitely not one of the first two so assume it's the last form (in which case we need the last paranthesised block) + strAttachPt = rlvGetLastParenthesisedText(pFolder->getName()); + } + } + else + { + // There's no paranthesised block, but it could still be "attachpt" or ".attachpt" (just strip away the '.' from the last one) + strAttachPt = pFolder->getName(); + if (RLV_FOLDER_PREFIX_HIDDEN == strAttachPt[0]) + strAttachPt.erase(0, 1); + } + return getAttachPointIndex(strAttachPt); +} + +// ============================================================================ +// RlvAttachmentLocks member functions +// + +RlvAttachmentLocks gRlvAttachmentLocks; + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + +#ifndef RLV_RELEASE + LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj); + // Assertion: the object specified by idAttachObj exists/is rezzed, is an attachment and always specifies the root + RLV_VERIFY( (pDbgObj) && (pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit()) ); +#endif // RLV_RELEASE + + m_AttachObjRem.insert(std::pair<LLUUID, LLUUID>(idAttachObj, idRlvObj)); + updateLockedHUD(); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + // NOTE: m_AttachPtXXX can contain duplicate <idxAttachPt, idRlvObj> pairs (ie @detach:spine=n,detach=n from an attachment on spine) + if (eLock & RLV_LOCK_REMOVE) + { + m_AttachPtRem.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj)); + updateLockedHUD(); + } + if (eLock & RLV_LOCK_ADD) + m_AttachPtAdd.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj)); +} + +// Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b +bool RlvAttachmentLocks::canAttach() const +{ + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + if (!isLockedAttachmentPoint(itAttachPt->first, RLV_LOCK_ADD)) + return true; + } + } + return false; +} + +// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +bool RlvAttachmentLocks::canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll /*=false*/) const +{ + // (fDetachAll) | (isLockedAttachment) + // =================================== + // F | F => unlocked attachment => return true + // F | T => locked attachment => keep going + // T | F => unlocked attachment => keep going + // T | T => locked attachment => return false + // -> inside the loop : (A xor (not B)) condition and return !fDetachAll + // -> outside the loop: return fDetachAll + // fDetachAll == false : return false => all attachments are locked + // fDetachAll == true : return true => all attachments are unlocked + if (pAttachPt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if ( (fDetachAll) ^ (!isLockedAttachment(*itAttachObj)) ) + return !fDetachAll; + } + } + return (pAttachPt) && (fDetachAll); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvAttachmentLocks::hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const +{ + if (pAttachPt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + if (isLockedAttachment(*itAttachObj)) + return true; + } + } + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +bool RlvAttachmentLocks::isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedAttachment(pObj); + + // If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem + RLV_ASSERT( (!pObj) || (pObj == pObj->getRootEdit()) ); + + // Loop over every object that has the specified attachment locked (but ignore any locks owned by idRlvObj) + for (rlv_attachobjlock_map_t::const_iterator itAttachObj = m_AttachObjRem.lower_bound(pObj->getID()), + endAttachObj = m_AttachObjRem.upper_bound(pObj->getID()); itAttachObj != endAttachObj; ++itAttachObj) + { + if (itAttachObj->second != idRlvObj) + return true; + } + return isLockedAttachmentPointExcept(RlvAttachPtLookup::getAttachPointIndex(pObj), RLV_LOCK_REMOVE, idRlvObj); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.0.5b +bool RlvAttachmentLocks::isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedAttachmentPoint(idxAttachPt, eLock); + + // Loop over every object that has the specified attachment point locked (but ignore any locks owned by idRlvObj) + if (eLock & RLV_LOCK_REMOVE) + { + for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (itAttachPt->second != idRlvObj) + return true; + } + } + if (eLock & RLV_LOCK_ADD) + { + for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (itAttachPt->second != idRlvObj) + return true; + } + } + return false; +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + +#ifndef RLV_RELEASE + // NOTE: pObj *can* be NULL [see comments for @detach=n in RlvHandler::onAddRemDetach()] + const LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj); + // Assertion: if the object exists then it's an attachment and always specifies the root + RLV_VERIFY( (!pDbgObj) || ((pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit())) ); +#endif // RLV_RELEASE + + // NOTE: try to remove the lock even if pObj isn't an attachment (ie in case the user was able to "Drop" it) + RLV_ASSERT( m_AttachObjRem.lower_bound(idAttachObj) != m_AttachObjRem.upper_bound(idAttachObj) ); // The lock should always exist + for (rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.lower_bound(idAttachObj), + endAttachObj = m_AttachObjRem.upper_bound(idAttachObj); itAttachObj != endAttachObj; ++itAttachObj) + { + if (idRlvObj == itAttachObj->second) + { + m_AttachObjRem.erase(itAttachObj); + updateLockedHUD(); + break; + } + } +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + if (eLock & RLV_LOCK_REMOVE) + { + RLV_ASSERT( m_AttachPtRem.lower_bound(idxAttachPt) != m_AttachPtRem.upper_bound(idxAttachPt) ); // The lock should always exist + for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (idRlvObj == itAttachPt->second) + { + m_AttachPtRem.erase(itAttachPt); + updateLockedHUD(); + break; + } + } + } + if (eLock & RLV_LOCK_ADD) + { + RLV_ASSERT( m_AttachPtAdd.lower_bound(idxAttachPt) != m_AttachPtAdd.upper_bound(idxAttachPt) ); // The lock should always exist + for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), + endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) + { + if (idRlvObj == itAttachPt->second) + { + m_AttachPtAdd.erase(itAttachPt); + break; + } + } + } +} + +// Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a +void RlvAttachmentLocks::updateLockedHUD() +{ + if (!isAgentAvatarValid()) + return; + + m_fHasLockedHUD = false; + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + if ( (pAttachPt) && (pAttachPt->getIsHUDAttachment()) && (hasLockedAttachment(pAttachPt)) ) + { + m_fHasLockedHUD = true; + break; + } + } + + // Reset HUD visibility and wireframe options if at least one HUD attachment is locked + if (m_fHasLockedHUD) + { + set_use_wireframe(false); + } +} + +// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvAttachmentLocks::verifyAttachmentLocks() +{ + bool fSuccess = true; + + // Verify attachment locks + rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.begin(), itCurrentObj; + while (itAttachObj != m_AttachObjRem.end()) + { + itCurrentObj = itAttachObj++; + + // If the attachment no longer exists (or is no longer attached) then we shouldn't be holding a lock to it + const LLViewerObject* pAttachObj = gObjectList.findObject(itCurrentObj->first); + if ( (!pAttachObj) || (!pAttachObj->isAttachment()) ) + { + m_AttachObjRem.erase(itCurrentObj); + fSuccess = false; + } + } + + return fSuccess; +} + +// ============================================================================ +// RlvAttachmentLockWatchdog member functions +// + +RlvAttachmentLockWatchdog::RlvAttachmentLockWatchdog() +{ +} + +// Checked: 2010-09-23 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +bool RlvAttachmentLockWatchdog::RlvWearInfo::isAddLockedAttachPt(S32 idxAttachPt) const +{ + // If idxAttachPt has no entry in attachPts then the attachment point wasn't RLV_LOCK_ADD restricted at the time we were instantiated + // [See RlvAttachmentLockWatchdog::onWearAttachment()] + return (attachPts.find(idxAttachPt) != attachPts.end()); +} + +// Checked: 2010-09-23 (RLVa-1.2.1d) | Added: RLVa-1.2.1d +void RlvAttachmentLockWatchdog::RlvWearInfo::dumpInstance() const +{ + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + std::string strItemId = idItem.asString(); + + std::string strTemp = llformat("Wear %s '%s' (%s)", + (RLV_WEAR_ADD == eWearAction) ? "add" : "replace", (pItem) ? pItem->getName().c_str() : "missing", strItemId.c_str()); + RLV_INFOS << strTemp.c_str() << RLV_ENDL; + + if (!attachPts.empty()) + { + std::string strEmptyAttachPt; + for (std::map<S32, uuid_vec_t>::const_iterator itAttachPt = attachPts.begin(); itAttachPt != attachPts.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = + get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL); + if (!itAttachPt->second.empty()) + { + for (uuid_vec_t::const_iterator itAttach = itAttachPt->second.begin(); itAttach != itAttachPt->second.end(); ++itAttach) + { + pItem = gInventory.getItem(*itAttach); + strItemId = (*itAttach).asString(); + + strTemp = llformat(" -> %s : %s (%s)", + pAttachPt->getName().c_str(), (pItem) ? pItem->getName().c_str() : "missing", strItemId.c_str()); + RLV_INFOS << strTemp.c_str() << RLV_ENDL; + } + } + else + { + if (!strEmptyAttachPt.empty()) + strEmptyAttachPt += ", "; + strEmptyAttachPt += pAttachPt->getName(); + } + } + if (!strEmptyAttachPt.empty()) + RLV_INFOS << " -> " << strEmptyAttachPt << " : empty" << RLV_ENDL; + } + else + { + RLV_INFOS << " -> no attachment point information" << RLV_ENDL; + } +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::detach(const LLViewerObject* pAttachObj) +{ + if (pAttachObj) + { + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID()); + if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) == m_PendingDetach.end()) + m_PendingDetach.push_back(pAttachObj->getAttachmentItemID()); + + gMessageSystem->sendReliable(gAgent.getRegionHost() ); + } +} + +// Checked: 2011-06-13 (RLVa-1.3.1b) | Modified: RLVa-1.3.1b +void RlvAttachmentLockWatchdog::detach(S32 idxAttachPt, const uuid_vec_t& idsAttachObjExcept) +{ + const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(idxAttachPt); + if (!pAttachPt) + return; + + std::vector<const LLViewerObject*> attachObjs; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + if (idsAttachObjExcept.end() == std::find(idsAttachObjExcept.begin(), idsAttachObjExcept.end(), pAttachObj->getID())) + attachObjs.push_back(pAttachObj); + } + + if (!attachObjs.empty()) + { + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + for (std::vector<const LLViewerObject*>::const_iterator itAttachObj = attachObjs.begin(); itAttachObj != attachObjs.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID()); + if (m_PendingDetach.end() == std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID())) + m_PendingDetach.push_back(pAttachObj->getAttachmentItemID()); + } + + gMessageSystem->sendReliable(gAgent.getRegionHost()); + } +} + +// Checked: 2010-09-23 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d +void RlvAttachmentLockWatchdog::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj); + const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null; + RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) ); + if ( (!idxAttachPt) || (idAttachItem.isNull()) ) + return; + + // Check if the attachment point has a pending "reattach" + rlv_attach_map_t::iterator itAttach = m_PendingAttach.lower_bound(idxAttachPt), itAttachEnd = m_PendingAttach.upper_bound(idxAttachPt); + if (itAttach != itAttachEnd) + { + bool fPendingReattach = false; + for (; itAttach != itAttachEnd; ++itAttach) + { + if (idAttachItem == itAttach->second.idItem) + { + fPendingReattach = true; + RlvBehaviourNotifyHandler::onReattach(pAttachPt, true); + m_PendingAttach.erase(itAttach); + break; + } + } + if (!fPendingReattach) + { + detach(pAttachObj); + RlvBehaviourNotifyHandler::onAttach(pAttachPt, false); + } + return; + } + + // Check if the attach was allowed at the time it was requested + rlv_wear_map_t::iterator itWear = m_PendingWear.find(idAttachItem); bool fAttachAllowed = true; + if (itWear != m_PendingWear.end()) + { + // We'll need to return the attachment point to its previous state if it was non-attachable + if (itWear->second.isAddLockedAttachPt(idxAttachPt)) + { + // Get the saved state of the attachment point (but do nothing if the item itself was already worn then) + std::map<S32, uuid_vec_t>::iterator itAttachPrev = itWear->second.attachPts.find(idxAttachPt); + RLV_ASSERT(itAttachPrev != itWear->second.attachPts.end()); + if (std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), idAttachItem) == itAttachPrev->second.end()) + { + // If it was empty we need to detach everything on the attachment point; if it wasn't we need to restore it to what it was + if (itAttachPrev->second.empty()) + { + detach(idxAttachPt); + } + else + { + // Iterate over all the current attachments and force detach any that shouldn't be there + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + + uuid_vec_t::iterator itAttach = + std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), pAttachObj->getAttachmentItemID()); + if (itAttach == itAttachPrev->second.end()) + detach(pAttachObj); + else + itAttachPrev->second.erase(itAttach); + } + + // Whatever is left is something that needs to be reattached + for (uuid_vec_t::const_iterator itAttach = itAttachPrev->second.begin(); + itAttach != itAttachPrev->second.end(); ++itAttach) + { + m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(*itAttach))); + } + } + fAttachAllowed = false; + } + } + else if (RLV_WEAR_REPLACE == itWear->second.eWearAction) + { + // Now that we know where this attaches to, check if we can actually perform a "replace" + uuid_vec_t idsAttachObjExcept; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + ((itAttachObj != pAttachPt->mAttachedObjects.end()) && (fAttachAllowed)); ++itAttachObj) + { + if ( (pAttachObj != *itAttachObj) && (gRlvAttachmentLocks.isLockedAttachment(*itAttachObj)) ) + { + // Fail if we encounter a non-detachable attachment (unless we're only replacing detachable attachments) + if (gSavedSettings.getBOOL("RLVaWearReplaceUnlocked")) + idsAttachObjExcept.push_back((*itAttachObj)->getID()); + else + fAttachAllowed = false; + } + } + + if (fAttachAllowed) + { + idsAttachObjExcept.push_back(pAttachObj->getID()); // Replace == allowed: detach everything except the new attachment + detach(idxAttachPt, idsAttachObjExcept); // or detach all *unlocked* attachments except the new attachment + } + else + { + detach(pAttachObj); // Replace != allowed: detach the new attachment + } + } + m_PendingWear.erase(itWear); // No need to start the timer since it should be running already if '!m_PendingWear.empty()' + } + RlvBehaviourNotifyHandler::onAttach(pAttachPt, fAttachAllowed); +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt) +{ + S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt); + const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null; + RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) ); + if ( (!idxAttachPt) || (idAttachItem.isNull()) ) + return; + + // If it's an attachment that's pending force-detach then we don't want to do anything (even if it's currently "remove locked") + rlv_detach_map_t::iterator itDetach = std::find(m_PendingDetach.begin(), m_PendingDetach.end(), idAttachItem); + if (itDetach != m_PendingDetach.end()) + { + m_PendingDetach.erase(itDetach); + RlvBehaviourNotifyHandler::onDetach(pAttachPt, true); + return; + } + + // If the attachment is currently "remove locked" then we should reattach it (unless it's already pending reattach) + bool fDetachAllowed = true; + if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) + { + bool fPendingAttach = false; + for (rlv_attach_map_t::const_iterator itReattach = m_PendingAttach.lower_bound(idxAttachPt), + itReattachEnd = m_PendingAttach.upper_bound(idxAttachPt); itReattach != itReattachEnd; ++itReattach) + { + if (itReattach->second.idItem == idAttachItem) + { + fPendingAttach = true; + break; + } + } + + // TODO-RLVa: [RLVa-1.2.1] we should re-add the item to COF as well to make sure it'll reattach when the user relogs + // -> check the call order in LLVOAvatarSelf::detachObject() since COF removal happens *after* we're called + if (!fPendingAttach) + { + m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(idAttachItem))); + startTimer(); + } + fDetachAllowed = false; + } + RlvBehaviourNotifyHandler::onDetach(pAttachPt, fDetachAllowed); +} + +// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b +void RlvAttachmentLockWatchdog::onSavedAssetIntoInventory(const LLUUID& idItem) +{ + for (rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin(); itAttach != m_PendingAttach.end(); ++itAttach) + { + if ( (!itAttach->second.fAssetSaved) && (idItem == itAttach->second.idItem) ) + { + LLAttachmentsMgr::instance().addAttachmentRequest(itAttach->second.idItem, itAttach->first, true, true); + itAttach->second.tsAttach = LLFrameTimer::getElapsedSeconds(); + } + } +} + +// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b +BOOL RlvAttachmentLockWatchdog::onTimer() +{ + // RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS" + F64 tsCurrent = LLFrameTimer::getElapsedSeconds(); + + // Garbage collect (failed) wear requests older than 60 seconds + rlv_wear_map_t::iterator itWear = m_PendingWear.begin(); + while (itWear != m_PendingWear.end()) + { + if (itWear->second.tsWear + 60 < tsCurrent) + m_PendingWear.erase(itWear++); + else + ++itWear; + } + + // Walk over the pending reattach list + rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin(); + while (itAttach != m_PendingAttach.end()) + { + // Sanity check - make sure the item is still in the user's inventory + if (gInventory.getItem(itAttach->second.idItem) == NULL) + { + m_PendingAttach.erase(itAttach++); + continue; + } + + // Force an attach if we haven't gotten a SavedAssetIntoInventory message after 15 seconds + // (or if it's been 30 seconds since we last tried to reattach the item) + bool fAttach = false; + if ( (!itAttach->second.fAssetSaved) && (itAttach->second.tsDetach + 15 < tsCurrent) ) + { + itAttach->second.fAssetSaved = true; + fAttach = true; + } + else if ( (itAttach->second.fAssetSaved) && (itAttach->second.tsAttach + 30 < tsCurrent) ) + { + fAttach = true; + } + + if (fAttach) + { + LLAttachmentsMgr::instance().addAttachmentRequest(itAttach->second.idItem, itAttach->first, true, true); + itAttach->second.tsAttach = tsCurrent; + } + + ++itAttach; + } + + return ( (m_PendingAttach.empty()) && (m_PendingDetach.empty()) && (m_PendingWear.empty()) ); +} + +// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +void RlvAttachmentLockWatchdog::onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction) +{ + // We only need to keep track of user wears if there's actually anything locked + RLV_ASSERT(idItem.notNull()); + if ( (idItem.isNull()) || (!isAgentAvatarValid()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + return; + + // If the attachment point this will end up being attached to is: + // - unlocked : nothing should happen (from RLVa's point of view) + // - RLV_LOCK_ADD: the new attachment should get detached and the current one(s) reattached (unless it's currently empty) + // - RLV_LOCK_REM: + // o eWearAction == RLV_WEAR_ADD : nothing should happen (from RLVa's point of view) + // o eWearAction == RLV_WEAR_REPLACE : examine whether the new attachment can indeed replace/detach the old one + RlvWearInfo infoWear(idItem, eWearAction); + RLV_ASSERT( (RLV_WEAR_ADD == eWearAction) || (RLV_WEAR_REPLACE == eWearAction) ); // One of the two, but never both + for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); + itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt) + { + const LLViewerJointAttachment* pAttachPt = itAttachPt->second; + // We only need to know which attachments were present for RLV_LOCK_ADD locked attachment points (and not RLV_LOCK_REM locked ones) + if (gRlvAttachmentLocks.isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD)) + { + uuid_vec_t attachObjs; + for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin(); + itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj) + { + const LLViewerObject* pAttachObj = *itAttachObj; + if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) != m_PendingDetach.end()) + continue; // Exclude attachments that are pending a force-detach + attachObjs.push_back(pAttachObj->getAttachmentItemID()); + } + infoWear.attachPts.insert(std::pair<S32, uuid_vec_t>(itAttachPt->first, attachObjs)); + } + } + + m_PendingWear.insert(std::pair<LLUUID, RlvWearInfo>(idItem, infoWear)); +#ifdef RLV_DEBUG + infoWear.dumpInstance(); +#endif // RLV_RELEASE + startTimer(); +} + +// ============================================================================ +// RlvWearableLocks member functions +// + +RlvWearableLocks gRlvWearableLocks; + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +void RlvWearableLocks::addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + // NOTE: m_WearableTypeXXX can contain duplicate <eType, idRlvObj> pairs (ie @remoutfit:shirt=n,remoutfit=n from the same object) + if (eLock & RLV_LOCK_REMOVE) + m_WearableTypeRem.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj)); + if (eLock & RLV_LOCK_ADD) + m_WearableTypeAdd.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool RlvWearableLocks::canRemove(LLWearableType::EType eType) const +{ + // NOTE: we return TRUE if the wearable type has at least one wearable that can be removed by the user + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++) + if (!isLockedWearable(gAgentWearables.getViewerWearable(eType, idxWearable))) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +bool RlvWearableLocks::hasLockedWearable(LLWearableType::EType eType) const +{ + // NOTE: we return TRUE if there is at least 1 non-removable wearable currently worn on this wearable type + for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++) + if (isLockedWearable(gAgentWearables.getViewerWearable(eType, idxWearable))) + return true; + return false; +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvWearableLocks::isLockedWearableExcept(const LLViewerWearable* pWearable, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedWearable(pWearable); + + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + return (pWearable) && (isLockedWearableTypeExcept(pWearable->getType(), RLV_LOCK_REMOVE, idRlvObj)); +} + +// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a +bool RlvWearableLocks::isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const +{ + if (idRlvObj.isNull()) + return isLockedWearableType(eType, eLock); + + // Loop over every object that marked the specified wearable type eLock type locked and skip over anything owned by idRlvObj + if (eLock & RLV_LOCK_REMOVE) + { + for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeRem.lower_bound(eType), + endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (itWearableType->second != idRlvObj) + return true; + } + } + if (eLock & RLV_LOCK_ADD) + { + for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), + endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (itWearableType->second != idRlvObj) + return true; + } + } + return false; +} + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +void RlvWearableLocks::removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock) +{ +/* + // Sanity check - make sure it's an object we know about + if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) ) + return; // If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE) +*/ + + if (eLock & RLV_LOCK_REMOVE) + { + RLV_ASSERT( m_WearableTypeRem.lower_bound(eType) != m_WearableTypeRem.upper_bound(eType) ); // The lock should always exist + for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeRem.lower_bound(eType), + endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (idRlvObj == itWearableType->second) + { + m_WearableTypeRem.erase(itWearableType); + break; + } + } + } + if (eLock & RLV_LOCK_ADD) + { + RLV_ASSERT( m_WearableTypeAdd.lower_bound(eType) != m_WearableTypeAdd.upper_bound(eType) ); // The lock should always exist + for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), + endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) + { + if (idRlvObj == itWearableType->second) + { + m_WearableTypeAdd.erase(itWearableType); + break; + } + } + } +} + +// ============================================================================ +// RlvFolderLocks member functions +// + +class RlvLockedDescendentsCollector : public LLInventoryCollectFunctor +{ +public: + RlvLockedDescendentsCollector(int eSourceTypeMask, RlvFolderLocks::ELockPermission ePermMask, ERlvLockMask eLockTypeMask) + : m_eSourceTypeMask(eSourceTypeMask), m_ePermMask(ePermMask), m_eLockTypeMask(eLockTypeMask) {} + /*virtual*/ ~RlvLockedDescendentsCollector() {} + /*virtual*/ bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) + { + return (pFolder) && (RlvFolderLocks::instance().isLockedFolderEntry(pFolder->getUUID(), m_eSourceTypeMask, m_ePermMask, m_eLockTypeMask)); + } +protected: + RlvFolderLocks::ELockPermission m_ePermMask; + int m_eSourceTypeMask; + ERlvLockMask m_eLockTypeMask; +}; + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +RlvFolderLocks::RlvFolderLocks() + : m_fLookupDirty(false), m_RootLockType(RLV_LOCK_NONE), m_cntLockAdd(0), m_cntLockRem(0) +{ + LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); + RlvInventory::instance().addSharedRootIDChangedCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +void RlvFolderLocks::addFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, + const LLUUID& idRlvObj, ERlvLockMask eLockType) +{ + // Sanity check - eLockType can be RLV_LOCK_ADD or RLV_LOCK_REMOVE but not both + RLV_ASSERT( (RLV_LOCK_ADD == eLockType) || (RLV_LOCK_REMOVE == eLockType) ); + + // NOTE: m_FolderXXX can contain duplicate folderlock_descr_t + m_FolderLocks.push_back(new folderlock_descr_t(idRlvObj, eLockType, lockSource, ePerm, eScope)); + + if (PERM_DENY == ePerm) + { + if (RLV_LOCK_REMOVE == eLockType) + m_cntLockRem++; + else if (RLV_LOCK_ADD == eLockType) + m_cntLockAdd++; + } + + if (!m_AttachmentChangeConnection.connected()) + m_AttachmentChangeConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvFolderLocks::onNeedsLookupRefresh, this)); + m_fLookupDirty = true; +} + +// Checked: 2011-03-28 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +bool RlvFolderLocks::getLockedFolders(const folderlock_source_t& lockSource, LLInventoryModel::cat_array_t& lockFolders) const +{ + S32 cntFolders = lockFolders.size(); + switch (lockSource.first) + { + case ST_ATTACHMENT: + { + RLV_ASSERT(typeid(LLUUID) == lockSource.second.type()) + const LLViewerObject* pObj = gObjectList.findObject(boost::get<LLUUID>(lockSource.second)); + if ( (pObj) && (pObj->isAttachment()) ) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(pObj->getAttachmentItemID()); + if ( (pItem) && (RlvInventory::instance().isSharedFolder(pItem->getParentUUID())) ) + { + LLViewerInventoryCategory* pItemFolder = gInventory.getCategory(pItem->getParentUUID()); + if (pItemFolder) + lockFolders.push_back(pItemFolder); + } + } + } + break; + case ST_FOLDER: + { + RLV_ASSERT(typeid(LLUUID) == lockSource.second.type()) + LLViewerInventoryCategory* pFolder = gInventory.getCategory(boost::get<LLUUID>(lockSource.second)); + if (pFolder) + lockFolders.push_back(pFolder); + } + break; + case ST_ROOTFOLDER: + { + LLViewerInventoryCategory* pFolder = gInventory.getCategory(gInventory.getRootFolderID()); + if (pFolder) + lockFolders.push_back(pFolder); + } + break; + case ST_SHAREDPATH: + { + RLV_ASSERT(typeid(std::string) == lockSource.second.type()) + LLViewerInventoryCategory* pSharedFolder = RlvInventory::instance().getSharedFolder(boost::get<std::string>(lockSource.second)); + if (pSharedFolder) + lockFolders.push_back(pSharedFolder); + } + break; + case ST_ATTACHMENTPOINT: + case ST_WEARABLETYPE: + { + RLV_ASSERT( ((ST_ATTACHMENTPOINT == lockSource.first) && (typeid(S32) == lockSource.second.type())) || + ((ST_WEARABLETYPE == lockSource.first) && (typeid(LLWearableType::EType) == lockSource.second.type())) ); + + uuid_vec_t idItems; + if (ST_ATTACHMENTPOINT == lockSource.first) + RlvCommandOptionGetPath::getItemIDs(RlvAttachPtLookup::getAttachPoint(boost::get<S32>(lockSource.second)), idItems); + else if (ST_WEARABLETYPE == lockSource.first) + RlvCommandOptionGetPath::getItemIDs(boost::get<LLWearableType::EType>(lockSource.second), idItems); + + LLInventoryModel::cat_array_t itemFolders; + if (RlvInventory::instance().getPath(idItems, itemFolders)) + lockFolders.insert(lockFolders.end(), itemFolders.begin(), itemFolders.end()); + } + break; + default: + return false; + }; + return cntFolders != lockFolders.size(); +} + +// Checked: 2011-11-26 (RLVa-1.5.4a) | Modified: RLVa-1.5.4a +bool RlvFolderLocks::getLockedItems(const LLUUID& idFolder, LLInventoryModel::item_array_t& lockItems) const +{ + S32 cntItems = lockItems.size(); + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + LLFindWearablesEx f(true, true); // Collect all worn items + gInventory.collectDescendentsIf(idFolder, folders, items, FALSE, f); + + // Generally several of the worn items will belong to the same folder so we'll cache the results of each lookup + std::map<LLUUID, bool> folderLookups; std::map<LLUUID, bool>::const_iterator itLookup; + + bool fItemLocked = false; + for (S32 idxItem = 0, cntItem = items.size(); idxItem < cntItem; idxItem++) + { + LLViewerInventoryItem* pItem = items.at(idxItem); + if (LLAssetType::AT_LINK == pItem->getActualType()) + pItem = pItem->getLinkedItem(); + if (!pItem) + continue; + + // Check the actual item's parent folder + const LLUUID& idItemParent = RlvInventory::getFoldedParent(pItem->getParentUUID(), true); + if ((itLookup = folderLookups.find(idItemParent)) != folderLookups.end()) + { + fItemLocked = itLookup->second; + } + else + { + fItemLocked = isLockedFolder(idItemParent, RLV_LOCK_REMOVE); + folderLookups.insert(std::pair<LLUUID, bool>(idItemParent, fItemLocked)); + } + + // Check the parent folders of any links to this item that exist under #RLV + if (!fItemLocked) + { + LLInventoryModel::item_array_t itemLinks; + LLInventoryModel::cat_array_t cats; + LLLinkedItemIDMatches f(pItem->getUUID()); + gInventory.collectDescendentsIf(RlvInventory::instance().getSharedRootID(), cats, itemLinks, LLInventoryModel::EXCLUDE_TRASH, f); + + for (LLInventoryModel::item_array_t::iterator itItemLink = itemLinks.begin(); + (itItemLink < itemLinks.end()) && (!fItemLocked); ++itItemLink) + { + LLViewerInventoryItem* pItemLink = *itItemLink; + + const LLUUID& idItemLinkParent = (pItemLink) ? RlvInventory::getFoldedParent(pItemLink->getParentUUID(), true) : LLUUID::null; + if ((itLookup = folderLookups.find(idItemLinkParent)) != folderLookups.end()) + { + fItemLocked = itLookup->second; + } + else + { + fItemLocked = isLockedFolder(idItemLinkParent, RLV_LOCK_REMOVE); + folderLookups.insert(std::pair<LLUUID, bool>(idItemLinkParent, fItemLocked)); + } + } + } + + if (fItemLocked) + lockItems.push_back(pItem); + } + + return cntItems != lockItems.size(); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +bool RlvFolderLocks::hasLockedFolderDescendent(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, + ERlvLockMask eLockTypeMask, bool fCheckSelf) const +{ + if (!hasLockedFolder(eLockTypeMask)) + return false; + if (m_fLookupDirty) + refreshLockedLookups(); + if ( (fCheckSelf) && (isLockedFolderEntry(idFolder, eSourceTypeMask, ePermMask, RLV_LOCK_ANY)) ) + return true; + + LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; + RlvLockedDescendentsCollector f(eSourceTypeMask, ePermMask, eLockTypeMask); + gInventory.collectDescendentsIf(idFolder, folders, items, FALSE, f, false); + return !folders.empty(); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +bool RlvFolderLocks::isLockedFolderEntry(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, ERlvLockMask eLockTypeMask) const +{ + for (folderlock_map_t::const_iterator itFolderLock = m_LockedFolderMap.lower_bound(idFolder), + endFolderLock = m_LockedFolderMap.upper_bound(idFolder); itFolderLock != endFolderLock; ++itFolderLock) + { + const folderlock_descr_t* pLockDescr = itFolderLock->second; + if ( (pLockDescr->lockSource.first & eSourceTypeMask) && (pLockDescr->eLockPermission & ePermMask) && + (pLockDescr->eLockType & eLockTypeMask) ) + { + return true; + } + } + return false; +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +bool RlvFolderLocks::isLockedFolder(LLUUID idFolder, ERlvLockMask eLockTypeMask, int eSourceTypeMask, std::list<folderlock_source_t>* pLockSourceList) const +{ + // Sanity check - if there are no folder locks then we don't have to actually do anything + if (!hasLockedFolder(eLockTypeMask)) + return false; + + // Folded folders will be locked if their "parent" is locked + idFolder = RlvInventory::getFoldedParent(idFolder, true); + if (idFolder.isNull()) + return false; + + if (m_fLookupDirty) + refreshLockedLookups(); + + // Walk up the folder tree and check if anything has 'idFolder' locked + std::list<LLUUID> idsRlvObjRem, idsRlvObjAdd; const LLUUID& idFolderRoot = gInventory.getRootFolderID(); LLUUID idFolderCur = idFolder; + while (idFolderRoot != idFolderCur) + { + // Iterate over any folder locks for 'idFolderCur' + for (folderlock_map_t::const_iterator itFolderLock = m_LockedFolderMap.lower_bound(idFolderCur), + endFolderLock = m_LockedFolderMap.upper_bound(idFolderCur); itFolderLock != endFolderLock; ++itFolderLock) + { + const folderlock_descr_t* pLockDescr = itFolderLock->second; + + // We can skip over the current lock if: + // - the current lock type doesn't match eLockTypeMask + // - it's a node lock and the current folder doesn't match + // - we encountered a PERM_ALLOW lock from the current lock owner before which supercedes any subsequent locks + // - the lock source type doesn't match the mask passed in eSourceTypeMask + ERlvLockMask eCurLockType = (ERlvLockMask)(pLockDescr->eLockType & eLockTypeMask); + std::list<LLUUID>* pidRlvObjList = (RLV_LOCK_REMOVE == eCurLockType) ? &idsRlvObjRem : &idsRlvObjAdd; + if ( (0 == eCurLockType) || ((SCOPE_NODE == pLockDescr->eLockScope) && (idFolder != idFolderCur)) || + (pidRlvObjList->end() != std::find(pidRlvObjList->begin(), pidRlvObjList->end(), pLockDescr->idRlvObj)) || + (0 == (pLockDescr->eLockType & eSourceTypeMask)) ) + { + continue; + } + + if (PERM_DENY == pLockDescr->eLockPermission) + { + if (pLockSourceList) + pLockSourceList->push_back(pLockDescr->lockSource); + else + return true; // Folder is explicitly denied, indicate locked folder to our caller (unless it wants a list of all lock sources) + } + else if (PERM_ALLOW == pLockDescr->eLockPermission) + { + pidRlvObjList->push_back(pLockDescr->idRlvObj); // Folder is explicitly allowed, save the owner so we can skip it from now on + } + } + + // Move up to the folder tree + const LLViewerInventoryCategory* pParent = gInventory.getCategory(idFolderCur); + idFolderCur = (pParent) ? pParent->getParentUUID() : idFolderRoot; + } + + if ( (pLockSourceList) && (!pLockSourceList->empty()) ) + { + // If we're asked to return a list, make sure it's sorted so we can compare them + pLockSourceList->sort([](const folderlock_source_t& lhs, const folderlock_source_t& rhs) { return lhs.first < rhs.first && lhs.second < rhs.second; }); + return true; + } + + // If we didn't encounter an explicit deny lock with no exception then the folder is locked if the entire inventory is locked down + return (m_RootLockType & eLockTypeMask) && (eSourceTypeMask & ST_ROOTFOLDER) && (idsRlvObjRem.empty()) && (idsRlvObjAdd.empty()); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Added: RLVa-1.3.0b +void RlvFolderLocks::onNeedsLookupRefresh() +{ + // NOTE: when removeFolderLock() removes the last folder lock we still want to refresh everything so mind the conditional OR assignment + m_fLookupDirty |= !m_FolderLocks.empty(); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +void RlvFolderLocks::refreshLockedLookups() const +{ + // + // Refresh locked folders + // + m_RootLockType = RLV_LOCK_NONE; + m_LockedFolderMap.clear(); + for (folderlock_list_t::const_iterator itFolderLock = m_FolderLocks.begin(); itFolderLock != m_FolderLocks.end(); ++itFolderLock) + { + const folderlock_descr_t* pLockDescr = *itFolderLock; + + LLInventoryModel::cat_array_t lockedFolders; const LLUUID& idFolderRoot = gInventory.getRootFolderID(); + if (getLockedFolders(pLockDescr->lockSource, lockedFolders)) + { + for (S32 idxFolder = 0, cntFolder = lockedFolders.size(); idxFolder < cntFolder; idxFolder++) + { + const LLViewerInventoryCategory* pFolder = lockedFolders.at(idxFolder); + if (idFolderRoot != pFolder->getUUID()) + m_LockedFolderMap.insert(std::pair<LLUUID, const folderlock_descr_t*>(pFolder->getUUID(), pLockDescr)); + else if (SCOPE_SUBTREE == pLockDescr->eLockScope) + m_RootLockType |= (U32)pLockDescr->eLockType; + } + } + } + m_fLookupDirty = false; + + // + // Refresh locked items (iterate over COF and filter out any items residing in a RLV_LOCK_REMOVE locked PERM_DENY folder) + // + m_LockedAttachmentRem.clear(); + m_LockedWearableRem.clear(); + + LLInventoryModel::item_array_t lockedItems; + if (getLockedItems(LLAppearanceMgr::instance().getCOF(), lockedItems)) + { + for (S32 idxItem = 0, cntItem = lockedItems.size(); idxItem < cntItem; idxItem++) + { + const LLViewerInventoryItem* pItem = lockedItems.at(idxItem); + switch (pItem->getType()) + { + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + m_LockedWearableRem.push_back(pItem->getLinkedUUID()); + break; + case LLAssetType::AT_OBJECT: + m_LockedAttachmentRem.push_back(pItem->getLinkedUUID()); + break; + default: + RLV_ASSERT(true); + break; + } + } + } + + // Remove any duplicate items we may have picked up + std::sort(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end()); + m_LockedAttachmentRem.erase(std::unique(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end()), m_LockedAttachmentRem.end()); + std::sort(m_LockedWearableRem.begin(), m_LockedWearableRem.end()); + m_LockedWearableRem.erase(std::unique(m_LockedWearableRem.begin(), m_LockedWearableRem.end()), m_LockedWearableRem.end()); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +void RlvFolderLocks::removeFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, + const LLUUID& idRlvObj, ERlvLockMask eLockType) +{ + // Sanity check - eLockType can be RLV_LOCK_ADD or RLV_LOCK_REMOVE but not both + RLV_ASSERT( (RLV_LOCK_ADD == eLockType) || (RLV_LOCK_REMOVE == eLockType) ); + + folderlock_descr_t lockDescr(idRlvObj, eLockType, lockSource, ePerm, eScope); RlvPredValuesEqual<folderlock_descr_t> f = { &lockDescr }; + folderlock_list_t::iterator itFolderLock = std::find_if(m_FolderLocks.begin(), m_FolderLocks.end(), f); + RLV_ASSERT( m_FolderLocks.end() != itFolderLock ); // The lock should always exist + if (m_FolderLocks.end() != itFolderLock) + { + delete *itFolderLock; + m_FolderLocks.erase(itFolderLock); + + if (PERM_DENY == ePerm) + { + if (RLV_LOCK_REMOVE == eLockType) + m_cntLockRem--; + else if (RLV_LOCK_ADD == eLockType) + m_cntLockAdd--; + } + m_fLookupDirty = true; + } +} + +// ============================================================================ diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h new file mode 100644 index 0000000000000000000000000000000000000000..62c4635121ce957c9481def0a1061f0cfa9791c7 --- /dev/null +++ b/indra/newview/rlvlocks.h @@ -0,0 +1,709 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_LOCKS_H +#define RLV_LOCKS_H + +#include "llagentwearables.h" +#include "lleventtimer.h" +#include "llvoavatarself.h" +#include "llviewerwearable.h" + +#include "rlvdefines.h" +#include "rlvcommon.h" + +// ============================================================================ +// RlvAttachPtLookup class declaration +// + +class RlvAttachPtLookup +{ +public: + static LLViewerJointAttachment* getAttachPoint(S32 idxAttachPt); + static LLViewerJointAttachment* getAttachPoint(const std::string& strText); + static LLViewerJointAttachment* getAttachPoint(const LLInventoryItem* pItem); + + static S32 getAttachPointIndex(std::string strText); + static S32 getAttachPointIndex(const LLViewerObject* pAttachObj); + static S32 getAttachPointIndex(const LLViewerJointAttachment* pAttachPt); + static S32 getAttachPointIndex(const LLInventoryCategory* pFolder); + static S32 getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks = true); + + static bool hasAttachPointName(const LLInventoryItem* pItem) { return (0 != getAttachPointIndex(pItem)); } +private: + static S32 getAttachPointIndexLegacy(const LLInventoryCategory* pFolder); + +public: + static void initLookupTable(); +private: + static std::map<std::string, S32> m_AttachPtLookupMap; +}; + +// ============================================================================ +// RlvAttachmentLocks class declaration +// + +// TODO-RLVa: [RLVa-1.2.1] Once everything is working for SL-2.0 thin out the member functions since a few of them are duplicates/unneeded +class RlvAttachmentLocks +{ +public: + RlvAttachmentLocks() : m_fHasLockedHUD(false) {} + +public: + // Adds an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment + void addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj); + // Adds an eLock type lock (held by idRlvObj) for the attachment point + void addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Returns TRUE if there is at least 1 non-detachable attachment currently attached to the attachment point + bool hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const; + // Returns TRUE if there is at least 1 eLock type locked attachment point (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + // - RLV_LOCK_REMOVE: specific attachment locked *or* any attachment point locked (regardless of whether it currently has attachments) + bool hasLockedAttachmentPoint(ERlvLockMask eLock) const; + // Returns TRUE if there is at least 1 non-detachable HUD attachment + bool hasLockedHUD() const { return m_fHasLockedHUD; } + + // Returns TRUE if the attachment is RLV_LOCK_REMOVE locked + bool isLockedAttachment(const LLViewerObject* pAttachObj) const; + // Returns TRUE if the attachment point is RLV_LOCK_REMOVE locked by anything other than idRlvObj + bool isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const; + // Returns TRUE if the attachment point is eLock type locked (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + bool isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const; + bool isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const; + + // Removes an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment + void removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj); + // Removes an eLock type lock (held by idRlvObj) for the attachment point + void removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Refreshes locked HUD attachment state + void updateLockedHUD(); + // Iterates over all current attachment and attachment point locks and verifies their status (returns TRUE if verification succeeded) + bool verifyAttachmentLocks(); + +protected: + // Returns TRUE if the attachment point is eLock type locked by anything other than idRlvObj + bool isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const; + + /* + * canAttach/canDetach trivial helper functions (note that a more approriate name might be userCanAttach/userCanDetach) + */ +public: + // Returns TRUE if there is at least one attachment point that can be attached to + bool canAttach() const; + // Returns TRUE if the inventory item can be attached by the user (and optionally provides the attachment point - which may be NULL) + ERlvWearMask canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut = NULL) const; + // Returns TRUE if the attachment point can be attached to by the user + ERlvWearMask canAttach(const LLViewerJointAttachment* pAttachPt) const; + + // Returns TRUE if the inventory item can be detached by the user + bool canDetach(const LLInventoryItem* pItem) const; + // Returns TRUE if the attachment point has at least one attachment that can be detached by the user + bool canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll = false) const; + + /* + * Member variables + */ +public: + typedef std::multimap<LLUUID, LLUUID> rlv_attachobjlock_map_t; + typedef std::multimap<S32, LLUUID> rlv_attachptlock_map_t; + // Accessors for RlvFloaterLocks + const rlv_attachptlock_map_t& getAttachPtLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_AttachPtAdd : m_AttachPtRem; } + const rlv_attachobjlock_map_t& getAttachObjLocks() { return m_AttachObjRem; } +private: + rlv_attachptlock_map_t m_AttachPtAdd; // Map of attachment points that can't be attached to (idxAttachPt -> idObj) + rlv_attachptlock_map_t m_AttachPtRem; // Map of attachment points whose attachments can't be detached (idxAttachPt -> idObj) + rlv_attachobjlock_map_t m_AttachObjRem; // Map of attachments that can't be detached (idAttachObj -> idObj) + + bool m_fHasLockedHUD; +}; + +extern RlvAttachmentLocks gRlvAttachmentLocks; + +// ============================================================================ +// RlvAttachmentLockWatchdog - Self contained class that automagically takes care of enforcing attachment locks (ie reattach-on-detach) +// + +// TODO-RLVa: [RLVa-1.2.1] This class really looks rather cluttered so look into cleaning it up/simplifying it a bit +class RlvAttachmentLockWatchdog : public LLSingleton<RlvAttachmentLockWatchdog> +{ + LLSINGLETON(RlvAttachmentLockWatchdog); +protected: + ~RlvAttachmentLockWatchdog() { delete m_pTimer; } + + /* + * Member functions + */ +protected: + // NOTE: detach does *not* respect attachment locks so use with care + void detach(const LLViewerObject* pAttachObj); + void detach(S32 idxAttachPt) { uuid_vec_t idsAttachObjExcept; detach(idxAttachPt, idsAttachObjExcept); } + void detach(S32 idxAttachPt, const uuid_vec_t& idsAttachObjExcept); + + void startTimer() { if (!m_pTimer) m_pTimer = new RlvAttachmentLockWatchdogTimer(this); } + + /* + * Event handlers + */ +public: + void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt); + void onSavedAssetIntoInventory(const LLUUID& idItem); + BOOL onTimer(); + void onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction); + void onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction); + + /* + * Member variables + */ +protected: + typedef std::list<LLUUID> rlv_detach_map_t; + rlv_detach_map_t m_PendingDetach; + + struct RlvReattachInfo + { + RlvReattachInfo(const LLUUID& itemid) : idItem(itemid), fAssetSaved(false), tsAttach(0) + { tsDetach = LLFrameTimer::getElapsedSeconds(); } + + LLUUID idItem; + bool fAssetSaved; + F64 tsDetach; + F64 tsAttach; + protected: + RlvReattachInfo(); + }; + typedef std::multimap<S32, RlvReattachInfo> rlv_attach_map_t; + rlv_attach_map_t m_PendingAttach; + + struct RlvWearInfo + { + RlvWearInfo(const LLUUID& itemid, ERlvWearMask wearaction) : idItem(itemid), eWearAction(wearaction) + { tsWear = LLFrameTimer::getElapsedSeconds(); } + + bool isAddLockedAttachPt(S32 idxAttachPt) const; + void dumpInstance() const; + + LLUUID idItem; + ERlvWearMask eWearAction; + F64 tsWear; + std::map<S32, uuid_vec_t> attachPts; + protected: + RlvWearInfo(); + }; + typedef std::map<LLUUID, RlvWearInfo> rlv_wear_map_t; + rlv_wear_map_t m_PendingWear; + + class RlvAttachmentLockWatchdogTimer : public LLEventTimer + { + public: + RlvAttachmentLockWatchdogTimer(RlvAttachmentLockWatchdog* pWatchdog) : LLEventTimer(10), m_pWatchdog(pWatchdog) {} + virtual ~RlvAttachmentLockWatchdogTimer() { m_pWatchdog->m_pTimer = NULL; } + virtual BOOL tick() { return m_pWatchdog->onTimer(); } + RlvAttachmentLockWatchdog* m_pWatchdog; + } *m_pTimer = nullptr; +}; + +// ============================================================================ +// RlvWearableLocks class declaration - modelled on RlvAttachmentLocks (attach pt = wearable type - attachment = wearable) +// + +class RlvWearableLocks +{ +public: + // Adds an eLock type lock (held by idRlvObj) for the wearable type + void addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Returns TRUE if there is at least 1 non-removable wearable currently worn on this wearable type + bool hasLockedWearable(LLWearableType::EType eType) const; + // Returns TRUE if there is at least 1 eLock type locked wearable type (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + // - RLV_LOCK_REMOVE: specific wearable locked *or* any wearable type locked (regardless of whether it currently has wearables) + bool hasLockedWearableType(ERlvLockMask eLock) const; + + // Removes an eLock type lock (held by idRlvObj) for the wearable type + void removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock); + + // Returns TRUE if the wearable is RLV_LOCK_REMOVE locked + bool isLockedWearable(const LLViewerWearable* pWearable) const; + // Returns TRUE if the wearable is RLV_LOCK_REMOVE locked by anything other than idRlvObj + bool isLockedWearableExcept(const LLViewerWearable* pWearable, const LLUUID& idRlvObj) const; + + // NOTE: isLockedWearableType doesn't check if a worn wearable is a specific wearable lock so don't let these be called by the outside +protected: + // Returns TRUE if the wearable type is eLock type locked + bool isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const; + // Returns TRUE if the wearable type is eLock type locked by anything other than idRlvObj + bool isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const; + + /* + * canWear/canRemove trivial helper functions (note that a more approriate name might be userCanWear/userCanRemove) + */ +public: + // Returns whether the inventory item can be worn by the user + ERlvWearMask canWear(const LLViewerInventoryItem* pItem) const; + // Returns whether the wearable type can be worn to by the user + ERlvWearMask canWear(LLWearableType::EType eType) const; + + // Returns TRUE if the inventory item can be removed by the user + bool canRemove(const LLInventoryItem* pItem) const; + // Returns TRUE if the wearable type has at least one wearable that can be removed by the user + bool canRemove(LLWearableType::EType eType) const; + + /* + * Member variables + */ +public: + typedef std::multimap<LLWearableType::EType, LLUUID> rlv_wearabletypelock_map_t; + // Accessors for RlvFloaterLocks + const rlv_wearabletypelock_map_t& getWearableTypeLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_WearableTypeAdd : m_WearableTypeRem; } +protected: + rlv_wearabletypelock_map_t m_WearableTypeAdd; + rlv_wearabletypelock_map_t m_WearableTypeRem; +}; + +extern RlvWearableLocks gRlvWearableLocks; + +// ============================================================================ +// RlvFolderLocks class declaration +// + +class RlvFolderLocks : public LLSingleton<RlvFolderLocks> +{ + friend class RlvLockedDescendentsCollector; + LLSINGLETON(RlvFolderLocks); +public: + // Specifies the source of a folder lock + enum ELockSourceType + { + ST_ATTACHMENT = 0x01, ST_ATTACHMENTPOINT = 0x02, ST_FOLDER = 0x04, ST_ROOTFOLDER = 0x08, + ST_SHAREDPATH = 0x10, ST_WEARABLETYPE = 0x20, ST_NONE= 0x00, ST_MASK_ANY = 0xFF + }; + typedef boost::variant<LLUUID, std::string, S32, LLWearableType::EType> lock_source_t; + typedef std::pair<ELockSourceType, lock_source_t> folderlock_source_t; + // Specifies options for the folder lock + enum ELockPermission { PERM_ALLOW = 0x1, PERM_DENY = 0x2, PERM_MASK_ANY = 0x3 }; + enum ELockScope { SCOPE_NODE, SCOPE_SUBTREE } ; + + struct folderlock_descr_t + { + LLUUID idRlvObj; + ERlvLockMask eLockType; + folderlock_source_t lockSource; + ELockPermission eLockPermission; + ELockScope eLockScope; + + folderlock_descr_t(const LLUUID& rlvObj, ERlvLockMask lockType, folderlock_source_t source, ELockPermission perm, ELockScope scope); + bool operator ==(const folderlock_descr_t& rhs) const; + }; + +public: + // Adds an eLock type lock (held by idRlvObj) for the specified folder source (with ePerm and eScope lock options) + void addFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, const LLUUID& idRlvObj, ERlvLockMask eLockType); + + // Returns TRUE if there is at least 1 non-detachable attachment as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool hasLockedAttachment() const; + // Returns TRUE if there is at least 1 eLock type PERM_DENY locked folder (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE) + bool hasLockedFolder(ERlvLockMask eLockTypeMask) const; + // Returns TRUE if the folder has a descendent folder lock with the specified charateristics + bool hasLockedFolderDescendent(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, + ERlvLockMask eLockTypeMask, bool fCheckSelf) const; + // Returns TRUE if there is at least 1 non-removable wearable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool hasLockedWearable() const; + // Returns TRUE if the attachment (specified by item UUID) is non-detachable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool isLockedAttachment(const LLUUID& idItem) const; + // Returns TRUE if the folder is locked as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool isLockedFolder(LLUUID idFolder, ERlvLockMask eLock, int eSourceTypeMask = ST_MASK_ANY, std::list<folderlock_source_t>* pLockSourceList = nullptr) const; + // Returns TRUE if the wearable (specified by item UUID) is non-removable as a result of a RLV_LOCK_REMOVE folder PERM_DENY lock + bool isLockedWearable(const LLUUID& idItem) const; + + // Removes an eLock type lock (held by idRlvObj) for the specified folder source (with ePerm and eScope lock options) + void removeFolderLock(const folderlock_source_t& lockSource, ELockPermission ePerm, ELockScope eScope, const LLUUID& idRlvObj, ERlvLockMask eLockType); + +protected: + // Returns TRUE if the folder has an explicit folder lock entry with the specified charateristics + bool isLockedFolderEntry(const LLUUID& idFolder, int eSourceTypeMask, ELockPermission ePermMask, ERlvLockMask eLockTypeMask) const; + + /* + * canXXX helper functions (note that a more approriate name might be userCanXXX) + */ +public: + bool canMoveFolder(const LLUUID& idFolder, const LLUUID& idFolderDest) const; + bool canRemoveFolder(const LLUUID& idFolder) const; + bool canRenameFolder(const LLUUID& idFolder) const; + bool canMoveItem(const LLUUID& idItem, const LLUUID& idFolderDest) const; + bool canRemoveItem(const LLUUID& idItem) const; + bool canRenameItem(const LLUUID& idItem) const; + + /* + * Cached item/folder look-up helper functions + */ +protected: + bool getLockedFolders(const folderlock_source_t& lockSource, LLInventoryModel::cat_array_t& lockFolders) const; + bool getLockedItems(const LLUUID& idFolder, LLInventoryModel::item_array_t& lockItems) const; + void onNeedsLookupRefresh(); + void refreshLockedLookups() const; + + /* + * Member variables + */ +public: + typedef std::list<const folderlock_descr_t*> folderlock_list_t; + // Accessors for RlvFloaterLocks + const folderlock_list_t& getFolderLocks() { return m_FolderLocks; } + const uuid_vec_t& getAttachmentLookups() { return m_LockedAttachmentRem; } + const uuid_vec_t& getWearableLookups() { return m_LockedWearableRem; } +protected: + boost::signals2::connection m_AttachmentChangeConnection; + + // Map of folder locks (idRlvObj -> lockDescr) + folderlock_list_t m_FolderLocks; // List of add and remove locked folder descriptions + S32 m_cntLockAdd; // Number of RLV_LOCK_ADD locked folders in m_FolderLocks + S32 m_cntLockRem; // Number of RLV_LOCK_REMOVE locked folders in m_FolderLocks + + // Cached item look-up variables + typedef std::multimap<LLUUID, const folderlock_descr_t*> folderlock_map_t; + mutable bool m_fLookupDirty; + mutable U32 m_RootLockType; + mutable uuid_vec_t m_LockedAttachmentRem; + mutable folderlock_map_t m_LockedFolderMap; + mutable uuid_vec_t m_LockedWearableRem; +private: + friend class LLSingleton<RlvFolderLocks>; +}; + +// ============================================================================ +// RlvAttachPtLookup inlined member functions +// + +// Checked: 2010-11-30 (RLVa-1.4.0b) | Added: RLVa-1.4.0b +inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(S32 idxAttachPt) +{ + return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d +inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const std::string& strText) +{ + return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(strText), (LLViewerJointAttachment*)NULL) : NULL; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b +inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const LLInventoryItem* pItem) +{ + return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(pItem), (LLViewerJointAttachment*)NULL) : NULL; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline S32 RlvAttachPtLookup::getAttachPointIndex(std::string strText) +{ + LLStringUtil::toLower(strText); + RLV_ASSERT(m_AttachPtLookupMap.size() > 0); + std::map<std::string, S32>::const_iterator itAttachPt = m_AttachPtLookupMap.find(strText); + return (itAttachPt != m_AttachPtLookupMap.end()) ? itAttachPt->second : 0; +} + +// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d +inline S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerObject* pObj) +{ + return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getAttachmentState()) : 0; +} + +// ============================================================================ +// RlvAttachmentLocks inlined member functions +// + +// Checked: 2011-05-22 (RLVa-1.3.1b) | Modified: RLVa-1.3.1b +inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut /*=NULL*/) const +{ + // The specified item can be attached if: + // - it doesn't specify an attachment point and there is at least one attachment point that can be attached to + // - the attachment point it specifies can be attached to + LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(pItem); + if (ppAttachPtOut) + *ppAttachPtOut = pAttachPt; + return ((canAttach()) && (pItem) && (!RlvFolderLocks::instance().isLockedFolder(pItem->getParentUUID(), RLV_LOCK_ADD))) + ? ((!pAttachPt) ? RLV_WEAR : canAttach(pAttachPt)) : RLV_WEAR_LOCKED; +} + +// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLViewerJointAttachment* pAttachPt) const +{ + // Non-attachable attachment point => RLV_WEAR_LOCKED + // One or more locked attachment(s) => RLV_WEAR_ADD + // Unlocked attachment(s) => RLV_WEAR_ADD | RLV_WEAR_REPLACE + // Empty attachment point => RLV_WEAR_ADD | RLV_WEAR_REPLACE + RLV_ASSERT(pAttachPt); // TODO-RLVa: [RLVa-1.2.1] Maybe it's better to just return something similar like above? + return + (ERlvWearMask)(((pAttachPt) && (!isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD))) + ? ((canDetach(pAttachPt, true)) ? RLV_WEAR_REPLACE : 0) | RLV_WEAR_ADD + : RLV_WEAR_LOCKED); +} + +// Checked: 2010-02-28 (RLVa-1.2.0) +inline bool RlvAttachmentLocks::canDetach(const LLInventoryItem* pItem) const +{ + const LLViewerObject* pAttachObj = + ((pItem) && (isAgentAvatarValid())) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL; + return (!pAttachObj) || (!isLockedAttachment(pAttachObj)); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b +inline bool RlvAttachmentLocks::hasLockedAttachmentPoint(ERlvLockMask eLock) const +{ + // Remove locks are more common so check those first + return + ((eLock & RLV_LOCK_REMOVE) && ((!m_AttachPtRem.empty()) || (!m_AttachObjRem.empty()) || (RlvFolderLocks::instance().hasLockedAttachment()))) || + ((eLock & RLV_LOCK_ADD) && (!m_AttachPtAdd.empty()) ); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b +inline bool RlvAttachmentLocks::isLockedAttachment(const LLViewerObject* pAttachObj) const +{ + // If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem + RLV_ASSERT( (!pAttachObj) || (pAttachObj == pAttachObj->getRootEdit()) ); + + // Object is locked if: + // - it's specifically marked as non-detachable (ie @detach=n) + // - it's attached to an attachment point that is RLV_LOCK_REMOVE locked (ie @remattach:<attachpt>=n) + // - it's part of a locked folder + return + (pAttachObj) && (pAttachObj->isAttachment()) && + ( (m_AttachObjRem.find(pAttachObj->getID()) != m_AttachObjRem.end()) || + (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachObj), RLV_LOCK_REMOVE)) || + ((!pAttachObj->isTempAttachment()) && (RlvFolderLocks::instance().isLockedAttachment(pAttachObj->getAttachmentItemID()))) ); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.0.5a +inline bool RlvAttachmentLocks::isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const +{ + return + ( (eLock & RLV_LOCK_REMOVE) && (m_AttachPtRem.find(idxAttachPt) != m_AttachPtRem.end()) ) || + ( (eLock & RLV_LOCK_ADD) && (m_AttachPtAdd.find(idxAttachPt) != m_AttachPtAdd.end()) ); +} + +// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a +inline bool RlvAttachmentLocks::isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const +{ + return (pAttachPt) && (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachPt), eLock)); +} + +// ============================================================================ +// RlvWearableLocks inlined member functions +// + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +inline bool RlvWearableLocks::canRemove(const LLInventoryItem* pItem) const +{ + // The specified item can be removed if its wearable can be removed + RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) ); + const LLViewerWearable* pWearable = (pItem) ? gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID()) : NULL; + return (pWearable) && (!isLockedWearable(pWearable)); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +inline ERlvWearMask RlvWearableLocks::canWear(const LLViewerInventoryItem* pItem) const +{ + // The specified item can be worn if the wearable type it specifies can be worn on + RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) ); + return ((pItem) && (!RlvFolderLocks::instance().isLockedFolder(pItem->getParentUUID(), RLV_LOCK_ADD))) + ? canWear(pItem->getWearableType()) : RLV_WEAR_LOCKED; +} + +// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +inline ERlvWearMask RlvWearableLocks::canWear(LLWearableType::EType eType) const +{ + // The specified wearable type can be worn on if: + // - the wearable type itself isn't RLV_LOCK_ADD locked => RLV_WEAR_ADD + // (and there are less than the maximum amount currently worn) + // - it doesn't have any non-removable wearables => RLV_WEAR_REPLACE | RLV_WEAR_ADD = RLV_WEAR + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + return (!isLockedWearableType(eType, RLV_LOCK_ADD)) + ? ((!hasLockedWearable(eType)) + ? RLV_WEAR + : (gAgentWearables.canAddWearable(eType)) ? RLV_WEAR_ADD : RLV_WEAR_LOCKED) + : RLV_WEAR_LOCKED; +} + +// Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a +inline bool RlvWearableLocks::hasLockedWearableType(ERlvLockMask eLock) const +{ + // Remove locks are more common so check those first + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + return ( (eLock & RLV_LOCK_REMOVE) && (!m_WearableTypeRem.empty()) ) || ( (eLock & RLV_LOCK_ADD) && (!m_WearableTypeAdd.empty()) ); +} + +// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.2.0a +inline bool RlvWearableLocks::isLockedWearable(const LLViewerWearable* pWearable) const +{ + // Wearable is locked if: + // - it's specifically marked as non-removable + // - it's worn on a wearable type that is RLV_LOCK_REMOVE locked + // - it's part of a locked folder + // TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do + RLV_ASSERT(pWearable); + return + (pWearable) && + ( (isLockedWearableType(pWearable->getType(), RLV_LOCK_REMOVE)) || (RlvFolderLocks::instance().isLockedWearable(pWearable->getItemID())) ); +} + +// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +inline bool RlvWearableLocks::isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const +{ + return + ( (eLock & RLV_LOCK_REMOVE) && (m_WearableTypeRem.find(eType) != m_WearableTypeRem.end()) ) || + ( (eLock & RLV_LOCK_ADD) && (m_WearableTypeAdd.find(eType) != m_WearableTypeAdd.end()) ); +} + +// ============================================================================ +// RlvAttachmentLockWatchdog inlined member functions +// + +// Checked: 2010-08-07 (RLVa-1.2.0i) | Added: RLVa-1.2.0i +inline void RlvAttachmentLockWatchdog::onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction) +{ + onWearAttachment(pItem->getLinkedUUID(), eWearAction); +} + +// ============================================================================ +// RlvFolderLocks member functions +// + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline RlvFolderLocks::folderlock_descr_t::folderlock_descr_t(const LLUUID& rlvObj, ERlvLockMask lockType, folderlock_source_t source, + ELockPermission perm, ELockScope scope) + : idRlvObj(rlvObj), eLockType(lockType), lockSource(source), eLockPermission(perm), eLockScope(scope) +{ +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::folderlock_descr_t::operator ==(const folderlock_descr_t& rhs) const +{ + return (idRlvObj == rhs.idRlvObj) && (eLockType == rhs.eLockType) && (lockSource == rhs.lockSource) && + (eLockPermission == rhs.eLockPermission) && (eLockScope == rhs.eLockScope); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canMoveFolder(const LLUUID& idFolder, const LLUUID& idFolderDest) const +{ + // Block moving the folder to destination if: + // - the folder (or one of its descendents) is explicitly locked + // - folder and destination are subject to different locks + // -> Possible combinations: + // * folder locked + destination unlocked => block move + // * folder unlocked + destination locked => block move + // * folder locked + destination locked => allow move only if both are subject to the same folder lock + // * folder unlocked + destination unlocked => allow move (special case of above since both locks are equal when there is none) + // => so the above becomes (isLockedFolder(A) == isLockedFolder(B)) && (lockA == lockB) + std::list<folderlock_source_t> locksSource, locksSourceDest; + return + (!hasLockedFolderDescendent(idFolder, ST_MASK_ANY, PERM_MASK_ANY, RLV_LOCK_ANY, true)) && + ( (isLockedFolder(idFolder, RLV_LOCK_ANY, ST_MASK_ANY, &locksSource) == isLockedFolder(idFolderDest, RLV_LOCK_ANY, ST_MASK_ANY, &locksSourceDest)) && + (locksSource == locksSourceDest) ); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRemoveFolder(const LLUUID& idFolder) const +{ + // Block removing a folder if: + // - the folder (or one of its descendents) is explicitly locked + // - the folder itself is locked (but disregard root folder locks) + return + (!hasLockedFolderDescendent(idFolder, ST_MASK_ANY, PERM_MASK_ANY, RLV_LOCK_ANY, true)) && + (!isLockedFolder(idFolder, RLV_LOCK_ANY, ST_MASK_ANY & ~ST_ROOTFOLDER)); +} + +// Checked: 2011-03-29 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRenameFolder(const LLUUID& idFolder) const +{ + // Block renaming a folder if: + // - the folder (or one of its descendents) is explicitly locked by: + // -> a "shared path" => renaming the folder would change the shared path and hence invalidate the lock + // -> an attachment point -| + // -> an attachment |--> renaming the folder to a "dot" (=invisible) folder would invalidate the lock + // -> a wearable type -| + return !hasLockedFolderDescendent(idFolder, ST_SHAREDPATH | ST_ATTACHMENT | ST_ATTACHMENTPOINT | ST_WEARABLETYPE, PERM_MASK_ANY, RLV_LOCK_ANY, true); +} + +// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canMoveItem(const LLUUID& idItem, const LLUUID& idFolderDest) const +{ + // Block moving the folder to destination if: + // - folder and destination are subject to different locks [see canMoveFolder() for more details] + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); const LLUUID& idFolder = (pItem) ? pItem->getParentUUID() : LLUUID::null; + int maskSource = ST_MASK_ANY & ~ST_ROOTFOLDER; std::list<folderlock_source_t> locksSource, locksSourceDest; + return + (idFolder.notNull()) && + (isLockedFolder(idFolder, RLV_LOCK_ANY, maskSource, &locksSource) == isLockedFolder(idFolderDest, RLV_LOCK_ANY, maskSource, &locksSourceDest)) && + (locksSource == locksSourceDest); +} + +// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRemoveItem(const LLUUID& idItem) const +{ + // Block removing items from locked folders (but disregard root folder locks) + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); const LLUUID& idFolder = (pItem) ? pItem->getParentUUID() : LLUUID::null; + int maskSource = ST_MASK_ANY & ~ST_ROOTFOLDER; + return (idFolder.notNull()) && (!isLockedFolder(idFolder, RLV_LOCK_ANY, maskSource)); +} + +// Checked: 2011-03-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0g +inline bool RlvFolderLocks::canRenameItem(const LLUUID& idItem) const +{ + // Items can always be renamed, regardless of folder locks + return true; +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::hasLockedAttachment() const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return !m_LockedAttachmentRem.empty(); +} + +// Checked: 2011-03-27 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g +inline bool RlvFolderLocks::hasLockedFolder(ERlvLockMask eLock) const +{ + // Remove locks are more common so check those first + return ((eLock & RLV_LOCK_REMOVE) && (m_cntLockRem)) || ((eLock & RLV_LOCK_ADD) && (m_cntLockAdd)); +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::hasLockedWearable() const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return !m_LockedWearableRem.empty(); +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::isLockedAttachment(const LLUUID& idItem) const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return (std::find(m_LockedAttachmentRem.begin(), m_LockedAttachmentRem.end(), idItem) != m_LockedAttachmentRem.end()); +} + +// Checked: 2010-11-30 (RLVa-1.3.0g) | Added: RLVa-1.3.0b +inline bool RlvFolderLocks::isLockedWearable(const LLUUID& idItem) const +{ + if (m_fLookupDirty) + refreshLockedLookups(); + return (std::find(m_LockedWearableRem.begin(), m_LockedWearableRem.end(), idItem) != m_LockedWearableRem.end()); +} + +// ============================================================================ + +#endif // RLV_LOCKS_H diff --git a/indra/newview/rlvmodifiers.cpp b/indra/newview/rlvmodifiers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce082254f2e72544fe6d9c6f71aa6fb14f740d60 --- /dev/null +++ b/indra/newview/rlvmodifiers.cpp @@ -0,0 +1,115 @@ +/** + * + * Copyright (c) 2009-2018, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" + +#include "rlvmodifiers.h" + +// ==================================================================================== +// RlvBehaviourModifierAnimator +// + +RlvBehaviourModifierAnimator::~RlvBehaviourModifierAnimator() +{ + if (!m_TimerHandle.isDead()) + m_TimerHandle.markDead(); +} + +void RlvBehaviourModifierAnimator::addTween(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod, RlvBehaviourModifierAnimationType eAnimType, const RlvBehaviourModifierValue& endValue, float nDuration) +{ + // Make sure we don't run two animations on the same modifier for the same object + const auto itTween = std::find_if(m_Tweens.begin(), m_Tweens.end(), [&idObject, eBhvrMod](const RlvBehaviourModifierTween& t) { return t.idObject == idObject && t.eBhvrMod == eBhvrMod; }); + if (m_Tweens.end() != itTween) + m_Tweens.erase(itTween); + + if (const RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(eBhvrMod)) + { + RlvBehaviourModifierTween newTween; + newTween.idObject = idObject; + newTween.eBhvrMod = eBhvrMod; + newTween.eAnimType = RlvBehaviourModifierAnimationType::Lerp; + newTween.nStartTime = LLTimer::getElapsedSeconds(); + newTween.nDuration = nDuration; + newTween.startValue = pBhvrModifier->getValue(); + newTween.endValue = endValue; + if (newTween.startValue.which() == newTween.endValue.which()) + { + if (m_TimerHandle.isDead()) + m_TimerHandle = (new AnimationTimer())->getHandle(); + m_Tweens.emplace_back(std::move(newTween)); + } + } +} + +void RlvBehaviourModifierAnimator::clearTweens(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod) +{ + m_Tweens.erase(std::remove_if(m_Tweens.begin(), m_Tweens.end(), + [&idObject, eBhvrMod](const RlvBehaviourModifierTween& cmpTween) + { + return cmpTween.idObject == idObject && ((cmpTween.eBhvrMod == eBhvrMod) || (RLV_MODIFIER_UNKNOWN == eBhvrMod)); + }), m_Tweens.end()); +} + +// ==================================================================================== +// RlvBehaviourModifierAnimator timer +// + +RlvBehaviourModifierAnimator::AnimationTimer::AnimationTimer() + : LLEventTimer(1.f / RLV_MODIFIER_ANIMATION_FREQUENCY) +{ +} + + +BOOL RlvBehaviourModifierAnimator::AnimationTimer::tick() +{ + RlvBehaviourModifierAnimator& modAnimatior = RlvBehaviourModifierAnimator::instance(); + const double curTime = LLTimer::getElapsedSeconds(); + + const auto activeTweens = modAnimatior.m_Tweens; + for (const auto& curTween : activeTweens) + { + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(curTween.eBhvrMod)) + { + // Update the modifier's value + float curFactor = (curTime - curTween.nStartTime) / curTween.nDuration; + if (curFactor < 1.0) + { + const auto& valueType = curTween.startValue.type(); + if (typeid(float) == valueType) + pBhvrModifier->setValue(lerp(boost::get<float>(curTween.startValue), boost::get<float>(curTween.endValue), curFactor), curTween.idObject); + else if (typeid(int) == valueType) + pBhvrModifier->setValue(lerp(boost::get<int>(curTween.startValue), boost::get<int>(curTween.endValue), curFactor), curTween.idObject); + else if (typeid(LLVector3) == valueType) + pBhvrModifier->setValue(lerp(boost::get<LLVector3>(curTween.startValue), boost::get<LLVector3>(curTween.endValue), curFactor), curTween.idObject); + } + else + { + pBhvrModifier->setValue(curTween.endValue, curTween.idObject); + auto itTween = std::find_if(modAnimatior.m_Tweens.begin(), modAnimatior.m_Tweens.end(), + [&curTween](const RlvBehaviourModifierTween& t) + { + // NOTE: implementation leak - taking advantage of the fact that we know there can only be one active tween per object/modifier/type combination + return t.idObject == curTween.idObject && t.eBhvrMod == curTween.eBhvrMod && t.eAnimType == curTween.eAnimType; + }); + modAnimatior.m_Tweens.erase(itTween); + } + } + } + + return modAnimatior.m_Tweens.empty(); +} + + // ==================================================================================== diff --git a/indra/newview/rlvmodifiers.h b/indra/newview/rlvmodifiers.h new file mode 100644 index 0000000000000000000000000000000000000000..3ccec3e71c3784773b6f977ed6758c233e8b467b --- /dev/null +++ b/indra/newview/rlvmodifiers.h @@ -0,0 +1,192 @@ +/** + * + * Copyright (c) 2009-2018, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#pragma once + +#include "llhandle.h" +#include "llsingleton.h" +#include "rlvhelper.h" + +// ==================================================================================== +// RlvBehaviourModifierHandler - Behaviour modifiers change handler class (use this if changes require code to be processed) +// + +template<ERlvBehaviourModifier eBhvrMod> +class RlvBehaviourModifierHandler : public RlvBehaviourModifier +{ +public: + //using RlvBehaviourModifier::RlvBehaviourModifier; // Needs VS2015 and up + RlvBehaviourModifierHandler(const std::string& strName, const RlvBehaviourModifierValue& defaultValue, bool fAddDefaultOnEmpty, RlvBehaviourModifierComp* pValueComparator) + : RlvBehaviourModifier(strName, defaultValue, fAddDefaultOnEmpty, pValueComparator) {} +protected: + void onValueChange() const override; +}; + +// ==================================================================================== +// RlvBehaviourModifierComp - Behaviour modifiers comparers (used for sorting) +// + +struct RlvBehaviourModifierComp +{ + virtual ~RlvBehaviourModifierComp() {} + virtual bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) + { + // Values that match the primary object take precedence (otherwise maintain relative ordering) + if ( (std::get<1>(rhs) == m_idPrimaryObject) && (std::get<1>(lhs) != m_idPrimaryObject) ) + return false; + return true; + } + + LLUUID m_idPrimaryObject; +}; + +struct RlvBehaviourModifierCompMin : public RlvBehaviourModifierComp +{ + bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override + { + if ( (m_idPrimaryObject.isNull()) || ((std::get<1>(lhs) == m_idPrimaryObject) && (std::get<1>(rhs) == m_idPrimaryObject)) ) + return std::get<0>(lhs) < std::get<0>(rhs); + return RlvBehaviourModifierComp::operator()(lhs, rhs); + } +}; + +struct RlvBehaviourModifierCompMax : public RlvBehaviourModifierComp +{ + bool operator()(const RlvBehaviourModifierValueTuple& lhs, const RlvBehaviourModifierValueTuple& rhs) override + { + if ( (m_idPrimaryObject.isNull()) || ((std::get<1>(lhs) == m_idPrimaryObject) && (std::get<1>(rhs) == m_idPrimaryObject)) ) + return std::get<0>(rhs) < std::get<0>(lhs); + return RlvBehaviourModifierComp::operator()(lhs, rhs); + } +}; + +// ==================================================================================== +// RlvBehaviourModifierAnimator - A class to animate behaviour modifiers +// + +enum class RlvBehaviourModifierAnimationType { Lerp }; + +struct RlvBehaviourModifierTween +{ + LLUUID idObject; + ERlvBehaviourModifier eBhvrMod; + RlvBehaviourModifierAnimationType eAnimType; + double nStartTime; + float nDuration; + RlvBehaviourModifierValue startValue; + RlvBehaviourModifierValue endValue; +}; + +class RlvBehaviourModifierAnimator : public LLSingleton<RlvBehaviourModifierAnimator> +{ + LLSINGLETON_EMPTY_CTOR(RlvBehaviourModifierAnimator); +public: + ~RlvBehaviourModifierAnimator() override; + + /* + * Member functions + */ +public: + void addTween(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod, RlvBehaviourModifierAnimationType eAnimType, const RlvBehaviourModifierValue& endValue, float nDuration); + void clearTweens(const LLUUID& idObject) { clearTweens(idObject, RLV_MODIFIER_UNKNOWN); } + void clearTweens(const LLUUID& idObject, ERlvBehaviourModifier eBhvrMod); + + /* + * Animation timer + */ +protected: + class AnimationTimer : public LLEventTimer, public LLHandleProvider<AnimationTimer> + { + public: + AnimationTimer(); + BOOL tick() override; + }; + + /* + * Member variables + */ +protected: + LLHandle<AnimationTimer> m_TimerHandle; + std::list< RlvBehaviourModifierTween> m_Tweens; +}; + +// ==================================================================================== +// RlvCachedBehaviourModifier - Provides an optimized way to access a modifier that's frequently accessed and rarely updated +// + +// Inspired by LLControlCache<T> +template<typename T> +class RlvBehaviourModifierCache : public LLRefCount, public LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier> +{ +public: + RlvBehaviourModifierCache(ERlvBehaviourModifier eModifier) + : LLInstanceTracker<RlvBehaviourModifierCache<T>, ERlvBehaviourModifier>(eModifier) + { + if (RlvBehaviourModifier* pBhvrModifier = RlvBehaviourDictionary::instance().getModifier(eModifier)) + { + mConnection = pBhvrModifier->getSignal().connect(boost::bind(&RlvBehaviourModifierCache<T>::handleValueChange, this, _1)); + mCachedValue = pBhvrModifier->getValue<T>(); + } + else + { + mCachedValue = {}; + RLV_ASSERT(false); + } + } + ~RlvBehaviourModifierCache() {} + + /* + * Member functions + */ +public: + const T& getValue() const { return mCachedValue; } +protected: + void handleValueChange(const RlvBehaviourModifierValue& newValue) { mCachedValue = boost::get<T>(newValue); } + + /* + * Member variables + */ +protected: + T mCachedValue; + boost::signals2::scoped_connection mConnection; +}; + +// Inspired by LLCachedControl<T> +template <typename T> +class RlvCachedBehaviourModifier +{ +public: + RlvCachedBehaviourModifier(ERlvBehaviourModifier eModifier) + { + if ((mCachedModifierPtr = RlvBehaviourModifierCache<T>::getInstance(eModifier)) == nullptr) + mCachedModifierPtr = new RlvBehaviourModifierCache<T>(eModifier); + } + + /* + * Operators + */ +public: + operator const T&() const { return mCachedModifierPtr->getValue(); } + const T& operator()() { return mCachedModifierPtr->getValue(); } + + /* + * Member variables + */ +protected: + LLPointer<RlvBehaviourModifierCache<T>> mCachedModifierPtr; +}; + +// ==================================================================================== diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd6e5831ce72e71df7c6032578164c4ccd579ba7 --- /dev/null +++ b/indra/newview/rlvui.cpp @@ -0,0 +1,429 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "llavataractions.h" // LLAvatarActions::profileVisible() +#include "llfloatersidepanelcontainer.h" +#include "llhudtext.h" // LLHUDText::refreshAllObjectText() +#include "llimview.h" // LLIMMgr::computeSessionID() +#include "llmoveview.h" // Movement panel (contains "Stand" and "Stop Flying" buttons) +#include "llnavigationbar.h" // Navigation bar +#include "llparcel.h" +#include "llpaneltopinfobar.h" +#include "llteleporthistory.h" +#include "lltoolmgr.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llvoavatar.h" +#include "roles_constants.h" // Group "powers" + +#include "rlvui.h" +#include "rlvhandler.h" +#include "rlvextensions.h" + +// ============================================================================ + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +RlvUIEnabler::RlvUIEnabler() +{ + // Connect us to the behaviour toggle signal + gRlvHandler.setBehaviourToggleCallback(boost::bind(&RlvUIEnabler::onBehaviourToggle, this, _1, _2)); + + // onRefreshHoverText() + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTALL, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTWORLD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTHUD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this))); + + // onToggleMovement + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_FLY, boost::bind(&RlvUIEnabler::onToggleMovement, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_ALWAYSRUN, boost::bind(&RlvUIEnabler::onToggleMovement, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TEMPRUN, boost::bind(&RlvUIEnabler::onToggleMovement, this))); + + // onToggleViewXXX + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWNOTE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWSCRIPT, boost::bind(&RlvUIEnabler::onToggleViewXXX, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWTEXTURE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this))); + + // onToggleXXX + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onToggleShowLoc, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWMINIMAP, boost::bind(&RlvUIEnabler::onToggleShowMinimap, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWWORLDMAP, boost::bind(&RlvUIEnabler::onToggleShowWorldMap, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onToggleUnsit, this))); + + // onToggleTp + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onToggleTp, this))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLM, boost::bind(&RlvUIEnabler::onToggleTp, this))); + + // onUpdateLoginLastLocation + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this, _1))); + m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this, _1))); +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType) +{ + bool fQuitting = LLApp::isQuitting(); + for (behaviour_handler_map_t::const_iterator itHandler = m_Handlers.lower_bound(eBhvr), endHandler = m_Handlers.upper_bound(eBhvr); + itHandler != endHandler; ++itHandler) + { + itHandler->second(fQuitting); + } +} + +// ============================================================================ + +// Checked: 2010-03-02 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onRefreshHoverText() +{ + // Refresh all hover text each time any of the monitored behaviours get set or unset + LLHUDText::refreshAllObjectText(); +} + +// Checked: 2010-03-02 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a +void RlvUIEnabler::onToggleMovement() +{ + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) && (gAgent.getFlying()) ) + gAgent.setFlying(FALSE); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_ALWAYSRUN)) && (gAgent.getAlwaysRun()) ) + gAgent.clearAlwaysRun(); + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_TEMPRUN)) && (gAgent.getTempRun()) ) + gAgent.clearTempRun(); + + // Force an update since the status only updates when the current parcel changes [see LLFloaterMove::postBuild()] + LLFloaterMove::sUpdateMovementStatus(); +} + +// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f +void RlvUIEnabler::onToggleShowLoc() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + + if (LLNavigationBar::instanceExists()) + LLNavigationBar::instance().refreshLocationCtrl(); + if (LLPanelTopInfoBar::instanceExists()) + LLPanelTopInfoBar::instance().update(); + + if (!fEnable) + { + // Hide the "About Land" floater if it's currently visible + if (LLFloaterReg::instanceVisible("about_land")) + LLFloaterReg::hideInstance("about_land"); + // Hide the "Region / Estate" floater if it's currently visible + if (LLFloaterReg::instanceVisible("region_info")) + LLFloaterReg::hideInstance("region_info"); + // Hide the "God Tools" floater if it's currently visible + if (LLFloaterReg::instanceVisible("god_tools")) + LLFloaterReg::hideInstance("god_tools"); + + // + // Manipulate the teleport history + // + + // If the last entry in the persistent teleport history matches the current teleport history entry then we should remove it + LLTeleportHistory* pTpHistory = LLTeleportHistory::getInstance(); + LLTeleportHistoryStorage* pTpHistoryStg = LLTeleportHistoryStorage::getInstance(); + if ( (pTpHistory) && (pTpHistory->getItems().size() > 0) && (pTpHistory->getCurrentItemIndex() >= 0) && + (pTpHistoryStg) && (pTpHistoryStg->getItems().size() > 0) ) + { + const LLTeleportHistoryItem& tpItem = pTpHistory->getItems().back(); + const LLTeleportHistoryPersistentItem& tpItemStg = pTpHistoryStg->getItems().back(); + if (pTpHistoryStg->compareByTitleAndGlobalPos(tpItemStg, LLTeleportHistoryPersistentItem(tpItem.mTitle, tpItem.mGlobalPos))) + { + // TODO-RLVa: [RLVa-1.2.2] Is there a reason why LLTeleportHistoryStorage::removeItem() doesn't trigger history changed? + pTpHistoryStg->removeItem(pTpHistoryStg->getItems().size() - 1); + pTpHistoryStg->mHistoryChangedSignal(-1); + } + } + + // Clear the current location in the teleport history + if (pTpHistory) + pTpHistory->updateCurrentLocation(gAgent.getPositionGlobal()); + } + else + { + // Reset the current location in the teleport history (also takes care of adding it to the persistent teleport history) + LLTeleportHistory* pTpHistory = LLTeleportHistory::getInstance(); + if ( (pTpHistory) && (NULL != gAgent.getRegion()) ) + pTpHistory->updateCurrentLocation(gAgent.getPositionGlobal()); + } + + // Start or stop filtering the "About Land" and "Region / Estate" floaters + if ( (!fEnable) && (!m_ConnFloaterShowLoc.connected()) ) + { + m_ConnFloaterShowLoc = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterShowLoc, this, _1, _2)); + m_ConnPanelShowLoc = LLFloaterSidePanelContainer::setValidateCallback(boost::bind(&RlvUIEnabler::filterPanelShowLoc, this, _1, _2, _3)); + } + else if ( (fEnable) && (m_ConnFloaterShowLoc.connected()) ) + { + m_ConnFloaterShowLoc.disconnect(); + m_ConnPanelShowLoc.disconnect(); + } +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleShowMinimap() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP); + + // Start or stop filtering showing the mini-map floater + if (!fEnable) + addGenericFloaterFilter("mini_map"); + else + removeGenericFloaterFilter("mini_map"); + + // Hide the mini-map floater if it's currently visible (or restore it if it was previously visible) + static bool fPrevVisibile = false; + if ( (!fEnable) && ((fPrevVisibile = LLFloaterReg::instanceVisible("mini_map"))) ) + LLFloaterReg::hideInstance("mini_map"); + else if ( (fEnable) && (fPrevVisibile) ) + LLFloaterReg::showInstance("mini_map"); + + // Break/reestablish the visibility connection for the nearby people panel embedded minimap instance + LLPanel* pPeoplePanel = LLFloaterSidePanelContainer::getPanel("people", "panel_people"); + LLPanel* pNetMapPanel = (pPeoplePanel) ? pPeoplePanel->findChild<LLPanel>("Net Map Panel", TRUE) : NULL; + RLV_ASSERT( (pPeoplePanel) && (pNetMapPanel) ); + if (pNetMapPanel) + { + pNetMapPanel->setMakeVisibleControlVariable( (fEnable) ? gSavedSettings.getControl("NearbyListShowMap").get() : NULL); + // Reestablishing the visiblity connection will show the panel if needed so we only need to take care of hiding it when needed + if ( (!fEnable) && (pNetMapPanel->getVisible()) ) + pNetMapPanel->setVisible(false); + } +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleShowWorldMap() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); + + // Hide the world map if it's currently visible + if ( (!fEnable) && (LLFloaterReg::instanceVisible("world_map")) ) + LLFloaterReg::hideInstance("world_map"); + + // Start or stop filtering opening the world map + if (!fEnable) + addGenericFloaterFilter("world_map"); + else + removeGenericFloaterFilter("world_map"); +} + +// Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a +void RlvUIEnabler::onToggleTp() +{ + // Disable the navigation bar "Home" button if both @tplm=n *and* @tploc=n restricted + LLButton* pNavBarHomeBtn = LLNavigationBar::getInstance()->findChild<LLButton>("home_btn"); + RLV_ASSERT(pNavBarHomeBtn); + if (pNavBarHomeBtn) + pNavBarHomeBtn->setEnabled(!(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC))); +} + +// Checked: 2010-03-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleUnsit() +{ + bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT); + + LLPanelStandStopFlying* pPanelStand = LLPanelStandStopFlying::getInstance(); + RLV_ASSERT(pPanelStand); + if (pPanelStand) + { + LLButton* pBtnStand = pPanelStand->findChild<LLButton>("stand_btn"); + RLV_ASSERT(pBtnStand); + if (pBtnStand) + pBtnStand->setEnabled(fEnable); + } +} + +// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +void RlvUIEnabler::onToggleViewXXX() +{ + // If any of the three are still active then we keep filtering + bool fHasViewXXX = (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || + (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)); + + // Start or stop filtering opening the preview floaters + if ( (fHasViewXXX) && (!m_ConnFloaterViewXXX.connected()) ) + m_ConnFloaterViewXXX = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterViewXXX, this, _1, _2)); + else if ( (!fHasViewXXX) && (m_ConnFloaterViewXXX.connected()) ) + m_ConnFloaterViewXXX.disconnect(); +} + +// Checked: 2010-04-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0c +void RlvUIEnabler::onUpdateLoginLastLocation(bool fQuitting) +{ + if (!fQuitting) + RlvSettings::updateLoginLastLocation(); +} + +// ============================================================================ + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName) +{ + m_FilteredFloaters.insert(strFloaterName); + + if (!m_ConnFloaterGeneric.connected()) + m_ConnFloaterGeneric = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterGeneric, this, _1, _2)); +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +void RlvUIEnabler::removeGenericFloaterFilter(const std::string& strFloaterName) +{ + std::multiset<std::string>::iterator itFloater = m_FilteredFloaters.find(strFloaterName); + RLV_ASSERT_DBG(itFloater != m_FilteredFloaters.end()); + m_FilteredFloaters.erase(itFloater); + + RLV_ASSERT_DBG(m_ConnFloaterGeneric.connected()); + if (m_FilteredFloaters.empty()) + m_ConnFloaterGeneric.disconnect(); +} + +// Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a +bool RlvUIEnabler::filterFloaterGeneric(const std::string& strName, const LLSD&) +{ + return m_FilteredFloaters.end() == m_FilteredFloaters.find(strName); +} + +// Checked: 2010-04-22 (RLVa-1.4.5) | Added: RLVa-1.2.0 +bool RlvUIEnabler::filterFloaterShowLoc(const std::string& strName, const LLSD&) +{ + if ("about_land" == strName) + return canViewParcelProperties(); + else if ("region_info" == strName) + return canViewRegionProperties(); + else if ("god_tools" == strName) + return false; + return true; +} + +// Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 +bool RlvUIEnabler::filterPanelShowLoc(const std::string& strFloater, const std::string&, const LLSD& sdKey) +{ + if ("places" == strFloater) + { + const std::string strType = sdKey["type"].asString(); + if ("create_landmark" == strType) + return false; + else if ("agent" == strType) + return canViewParcelProperties(); + } + return true; +} + +// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a +bool RlvUIEnabler::filterFloaterViewXXX(const std::string& strName, const LLSD&) +{ + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) && ("preview_notecard" == strName) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD); + return false; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (("preview_script" == strName) || ("preview_scriptedit" == strName)) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT); + return false; + } + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)) && ("preview_texture" == strName) ) + { + RlvUtil::notifyBlockedViewXXX(LLAssetType::AT_TEXTURE); + return false; + } + return true; +} + +// ============================================================================ + +// Checked: 2012-02-09 (RLVa-1.4.5) | Modified: RLVa-1.4.5 +bool RlvUIEnabler::canViewParcelProperties() +{ + // We'll allow "About Land" as long as the user has the ability to return prims (through ownership or through group powers) + bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + // RELEASE-RLVa: [SL-3.2] Check that opening the "About Land" floater still sets focus to the current parcel is none is selected + const LLParcel* pParcel = NULL; + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) + { + pParcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + } + else + { + LLParcelSelection* pParcelSel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection(); + if (pParcelSel->hasOthersSelected()) + return false; + pParcel = pParcelSel->getParcel(); + } + + // Ideally we could just use LLViewerParcelMgr::isParcelOwnedByAgent(), but that has that sneaky exemption for "god-like" + if (pParcel) + { + const LLUUID& idOwner = pParcel->getOwnerID(); + if ( (idOwner != gAgent.getID()) ) + { + S32 count = gAgent.mGroups.size(); + for (S32 i = 0; i < count; ++i) + { + if (gAgent.mGroups.at(i).mID == idOwner) + { + fShow = ((gAgent.mGroups.at(i).mPowers & GP_LAND_RETURN) > 0); + break; + } + } + } + else + { + fShow = true; + } + } + } + return fShow; +} + +// Checked: 2010-04-20 (RLVa-1.4.5) | Modified: RLVa-1.2.0 +bool RlvUIEnabler::canViewRegionProperties() +{ + // We'll allow "Region / Estate" if the user is either the region owner or an estate manager + bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + // [See LLRegion::canManageEstate() but without the "god-like" exception] + const LLViewerRegion* pRegion = gAgent.getRegion(); + if (pRegion) + fShow = (pRegion->isEstateManager()) || (pRegion->getOwner() == gAgent.getID()); + } + return fShow; +} + +// Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f +bool RlvUIEnabler::hasOpenIM(const LLUUID& idAgent) +{ + LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent); + return (NULL != LLFloaterReg::findInstance("impanel", idSession)); +} + +// Checked: 2011-11-04 (RLVa-1.4.4a) | Modified: RLVa-1.4.4a +bool RlvUIEnabler::hasOpenProfile(const LLUUID& idAgent) +{ + // -> SL-2.1.0 added the ability to "share" inventory by dropping it on the avatar picker floater so we should check for that + // -> we can drag/drop inventory onto calling cards but probably noone knows about it and it would be too involved to check for that + // TODO-RLVa: [RLVa-1.2.1] Check the avatar picker as well + + // Check if the user has the specified agent's profile open + return LLAvatarActions::profileVisible(idAgent); +} + +// ============================================================================ diff --git a/indra/newview/rlvui.h b/indra/newview/rlvui.h new file mode 100644 index 0000000000000000000000000000000000000000..c6f945a2c5a60e04f60fab94571e71f599bae389 --- /dev/null +++ b/indra/newview/rlvui.h @@ -0,0 +1,94 @@ +/** + * + * Copyright (c) 2009-2011, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_UI_H +#define RLV_UI_H + +#include "llfloaterreg.h" +#include "llsingleton.h" + +#include "rlvdefines.h" + +// ============================================================================ +// RlvUIEnabler - self-contained class that handles disabling or reenabling certain aspects of the viewer's UI +// + +class RlvUIEnabler : public LLSingleton<RlvUIEnabler> +{ + friend class RlvHandler; + LLSINGLETON(RlvUIEnabler); +protected: + /* + * Signal callbacks + */ +public: + void onBehaviourToggle(ERlvBehaviour eBhvr, ERlvParamType eType); // RlvHandler::rlv_behaviour_signal_t + + /* + * Behaviour handlers + */ +protected: + void onRefreshHoverText(); // showloc, shownames, showhovertext(all|world|hud) + void onToggleMovement(); // fly, alwaysrun and temprun + void onToggleShowLoc(); // showloc + void onToggleShowMinimap(); // showminimap + void onToggleShowWorldMap(); // showworldmap + void onToggleTp(); // tploc and tplm + void onToggleUnsit(); // unsit + void onToggleViewXXX(); // viewnote, viewscript, viewtexture + void onUpdateLoginLastLocation(bool fQuitting); // tploc and unsit + + /* + * Floater and sidebar validation callbacks + */ +public: + void addGenericFloaterFilter(const std::string& strFloaterName); + void removeGenericFloaterFilter(const std::string& strFloaterName); + +protected: + bool filterFloaterGeneric(const std::string&, const LLSD&); + boost::signals2::connection m_ConnFloaterGeneric; + bool filterFloaterShowLoc(const std::string&, const LLSD& ); + boost::signals2::connection m_ConnFloaterShowLoc; // showloc + bool filterFloaterViewXXX(const std::string&, const LLSD&); + boost::signals2::connection m_ConnFloaterViewXXX; // viewnote, viewscript, viewtexture + + bool filterPanelShowLoc(const std::string&, const std::string&, const LLSD& ); + boost::signals2::connection m_ConnPanelShowLoc; // showloc + + /* + * Helper functions + */ +public: + static bool canViewParcelProperties(); // showloc + static bool canViewRegionProperties(); // showloc + static bool hasOpenIM(const LLUUID& idAgent); // shownames + static bool hasOpenProfile(const LLUUID& idAgent); // shownames + + /* + * Member variables + */ +protected: + typedef boost::function<void(bool)> behaviour_handler_t; + typedef std::multimap<ERlvBehaviour, behaviour_handler_t> behaviour_handler_map_t; + behaviour_handler_map_t m_Handlers; + + std::multiset<std::string> m_FilteredFloaters; +}; + +// ============================================================================ + +#endif // RLV_UI_H diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 5917a0b529e3de12cb634bc301d9503fba01370f..e084b9eaad8d6a286aea32de3a79b5afadc59e6c 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -187,6 +187,30 @@ <menu_item_call label="Rempler, Stöße & Schläge" name="Bumps, Pushes &amp; Hits"/> <menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/> </menu> + + <menu label="RLVa" name="RLVa Main"> + <menu label="Entwickler" name="Debug"> + <menu_item_check label="RLVa Menü in der Leiste anzeigen" name="Show Top-level RLVa Menu" /> + <menu_item_check label="Debug Nachrichten anzeigen" name="Show Debug Messages" /> + <menu_item_check label="Hide Unset or Duplicate Messages" name="Hide Unset or Duplicate Messages" /> + <menu_item_check label="Fehlermeldungen anzeigen" name="Show Assertion Failures" /> + <menu_item_check label="Gesperrte Layer verstecken" name="Hide Locked Layers" /> + <menu_item_check label="Gesperrte Teile verstecken" name="Hide Locked Attachments" /> + <menu_item_check label="Enable Legacy Naming" name="Enable Legacy Naming" /> + <menu_item_check label="Shared Wear einschalten" name="Enable Shared Wear" /> + <menu_item_check label="Objekte beim anziehen umbenennen" name="Rename Shared Items on Wear" /> + <menu_item_check label="Sperren..." name="Locks" /> + </menu> + + <menu_item_check label="OOC Chat erlauben" name="Allow OOC Chat" /> + <menu_item_check label="Senden an #RLV verbieten" name="Forbid Give to #RLV" /> + <menu_item_check label="Gefilterten Chat anzeigen" name="Show Filtered Chat" /> + <menu_item_check label="Namensschilder anzeigen" name="Show Name Tags" /> + <menu_item_check label="Anziehen ersetzt unverschlossenes" name="Wear Replaces Unlocked" /> + <menu_item_check label="Einschränkungen..." name="Restrictions" /> + <menu_item_check label="Nachrichten..." name="Strings" /> + </menu> + <menu label="Erweitert" name="Advanced"> <menu_item_call label="Textur neu laden" name="Rebake Texture"/> <menu_item_call label="UI-Größe auf Standard setzen" name="Set UI Size to Default"/> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 71f4d811954223ac8b6046039e85c531f75b3d9f..fb683ee1651075de3e98b0f7937e1bccf8839054 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -10,6 +10,7 @@ title="ABOUT [CAPITALIZED_APP_NAME]" width="500"> +RestrainedLove API: [RLV_VERSION] <tab_container follows="all" top="25" diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml index b8893e11d90207b5430afd4630aadccc0f57fc44..ad66f37d3cb8b1ee6b96fe3dee63b9f3d9d58604 100644 --- a/indra/newview/skins/default/xui/en/floater_map.xml +++ b/indra/newview/skins/default/xui/en/floater_map.xml @@ -14,9 +14,10 @@ save_rect="true" save_visibility="true" width="200"> + <!-- RLVa shows the anonymized name on the regular tooltip when @shownames=n restricted (rather than show the avatar inspector) --> <floater.string name="ToolTipMsg"> - [REGION](Double-click to open Map, shift-drag to pan) + [AGENT][REGION](Double-click to open Map, shift-drag to pan) </floater.string> <floater.string name="AltToolTipMsg"> diff --git a/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml new file mode 100644 index 0000000000000000000000000000000000000000..61c81caa5e95e5b660b13cb523e302f94e1a710f --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_close="true" + can_minimize="true" + can_resize="true" + height="300" + min_height="300" + min_width="450" + name="rlv_behaviours" + save_rect="true" + save_visibility="false" + single_instance="true" + title="ACTIVE RLV RESTRICTIONS" + width="450"> + <tab_container + follows="all" + layout="topleft" + left="8" + name="behaviour_tab" + height="266" + right="-8" + tab_height="23" + tab_min_width="120" + tab_position="top" + top="0" > + <panel + follows="all" height="265" + label="RESTRICTIONS" + layout="topleft" + name="behaviour_panel" + top="0"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="266" + layout="topleft" + multi_select="false" + name="behaviour_list" + sort_column="0" + tool_tip="List of current RLVa restrictions." + top_pad="0" > + <scroll_list.columns label="Restriction" name="behaviour" width="80" /> + <scroll_list.columns label="Object Name" name="issuer" /> + </scroll_list> + </panel> + <panel + follows="all" height="265" + label="EXCEPTIONS" + layout="topleft" + name="exception_panel" + top="0"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="266" + layout="topleft" + multi_select="false" + name="exception_list" + sort_column="0" + tool_tip="List of current RLVa exceptions." + top_pad="0" > + <scroll_list.columns label="Exception" name="behaviour" width="80" /> + <scroll_list.columns label="Source" name="option" width="105" /> + <scroll_list.columns label="Object Name" name="issuer" /> + </scroll_list> + </panel> + <panel + follows="all" height="265" + label="MODIFIERS" + layout="topleft" + name="modifier_panel" + top="0"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="266" + layout="topleft" + multi_select="false" + name="modifier_list" + sort_column="0" + tool_tip="List of current RLVa modifiers." + top_pad="0" > + <scroll_list.columns label="Modifier" name="modifier" width="105" /> + <scroll_list.columns label="Value" name="value" width="105" /> + <scroll_list.columns label="Primary Object" name="primary" /> + </scroll_list> + </panel> + </tab_container> + <panel + background_visible="false" + follows="left|right|bottom" + height="25" + label="bottom_panel" + layout="topleft" + name="bottom_panel" + top_pad="0"> + <button + image_hover_unselected="Toolbar_Left_Over" + image_overlay="Copy" + image_overlay_alignment="left" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + label="Copy to Clipboard" + left="0" + name="copy_btn" + top="1" + width="150" /> + <icon + follows="left|right" + image_name="Toolbar_Right_Off" + left_pad="1" + name="dummy_icon" + top="1" + right="-1" /> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_rlv_console.xml b/indra/newview/skins/default/xui/en/floater_rlv_console.xml new file mode 100644 index 0000000000000000000000000000000000000000..8c09e7dacc425fd18eda72106607d968762477bb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_console.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_resize="true" + height="400" + layout="topleft" + min_height="300" + min_width="300" + name="rlv_console" + title="RLVa console" + width="600" + > + <text_editor + follows="all" + left="10" + length="1" + font="Monospace" + height="366" + ignore_tab="false" + layout="topleft" + max_length="65536" + name="console_output" + read_only="true" + track_end="true" + type="string" + width="576" + word_wrap="true" + > + </text_editor> + <line_editor + border_style="line" + border_thickness="1" + bottom_delta="20" + follows="left|right|bottom" + font="SansSerif" + height="19" + layout="topleft" + max_length_chars="127" + name="console_input" + top_delta="0" + width="576" + > + </line_editor> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_rlv_locks.xml b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6665bcef2a6d5dfc4b585b5c84f220d31ae9386 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_close="true" + can_minimize="true" + can_resize="true" + height="200" + min_height="200" + min_width="500" + name="rlvLocks" + save_rect="true" + save_visibility="false" + single_instance="true" + positioning="cascading" + reuse_instance="true" + title="ACTIVE RLV LOCKS" + width="500"> + <panel + class="panel_rlvLocks" + filename="panel_rlv_locks.xml" + layout="topleft" + left="9" + name="panel_rlvLocks" + right="-8" + top="0" /> +</floater> \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/floater_rlv_strings.xml b/indra/newview/skins/default/xui/en/floater_rlv_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b31f99fb4eab7e8cbc7a2339cc0516b77a2d4eb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_rlv_strings.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_minimize="false" + height="215" + layout="topleft" + legacy_header_height="18" + name="rlva_strings" + title="RLVa Strings" + width="340"> + <combo_box + allow_text_entry="false" + follows="top|left" + height="22" + layout="topleft" + left="12" + max_chars="255" + name="string_list" + top="25" + width="316" /> + <text_editor + enabled="false" + height="60" + layout="topleft" + left_delta="0" + name="string_descr" + top_pad="5" + width="317" + word_wrap="true" /> + <text_editor + enabled="true" + height="60" + layout="topleft" + left_delta="0" + name="string_value" + top_pad="5" + width="316" + word_wrap="true" /> + <panel + follows="top|left" + height="25" + layout="topleft" + left="10" + name="bottom_panel" + top="180" + right="-8"> + <button + follows="top|left" + image_hover_unselected="Toolbar_Left_Over" + image_overlay="Refresh_Off" + image_overlay_alignment="left" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + label="Reset to default" + layout="topleft" + left="0" + name="default_btn" + top="1" + width="140" > + <button.commit_callback + function="ClickDefault" /> + </button> + <icon + follows="left|right" + image_name="Toolbar_Right_Off" + left_pad="1" + name="dummy_icon" + top="1" + right="-1" /> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 38f4b7715f6b7a3257efd65afc2e8944323308c8..b955d8313f7a677538ec9e46eeb8797ce75cca76 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -9,6 +9,8 @@ <menu_item_call.on_click function="ShowAgentProfile" parameter="hit object" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call enabled="false" @@ -24,6 +26,8 @@ name="Send IM..."> <menu_item_call.on_click function="Avatar.SendIM" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call label="Call" @@ -36,8 +40,10 @@ <menu_item_call label="Invite to Group" name="Invite..."> - <menu_item_call.on_click + <menu_item_call.on_click function="Avatar.InviteToGroup" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_separator /> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml index f9fb8479107228845208d6da6cdbbce61b165bd0..f2babde290b0fbcdb64eaedf1a14ab41572161a1 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml @@ -9,6 +9,8 @@ <menu_item_call.on_click function="ShowAgentProfile" parameter="hit object" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call enabled="false" @@ -24,6 +26,8 @@ name="Send IM..."> <menu_item_call.on_click function="Avatar.SendIM" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_call label="Call" @@ -36,8 +40,10 @@ <menu_item_call label="Invite to Group" name="Invite..."> - <menu_item_call.on_click + <menu_item_call.on_click function="Avatar.InviteToGroup" /> + <menu_item_call.on_enable + function="RLV.CanShowName" /> </menu_item_call> <menu_item_separator /> @@ -117,6 +123,8 @@ name="Pay..."> <menu_item_call.on_click function="PayObject" /> + <menu_item_call.on_enable + function="EnablePayAvatar" /> </menu_item_call> <menu_item_separator /> diff --git a/indra/newview/skins/default/xui/en/menu_land.xml b/indra/newview/skins/default/xui/en/menu_land.xml index 2ad5cbbe951cd561d4b72ab58fa5afb16380842b..3a7f24fdf5bcd30725cd7fad0ff7a4e760886ea9 100644 --- a/indra/newview/skins/default/xui/en/menu_land.xml +++ b/indra/newview/skins/default/xui/en/menu_land.xml @@ -8,6 +8,9 @@ <menu_item_call.on_click function="Floater.Show" parameter="about_land" /> + <menu_item_call.on_enable + function="Floater.CanShow" + parameter="about_land" /> </menu_item_call> <!-- <menu_item_call label="Go Here" diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml index e3a39a1242748c8b73874fc851b73cdd77f1db4a..bdd4e230b949b0327f107364c1ab29eabd5aae83 100644 --- a/indra/newview/skins/default/xui/en/menu_place_add_button.xml +++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml @@ -23,5 +23,8 @@ <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> </menu> diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml index 1aeb166e01570aaccb4ead89d93c7a887e3a4cad..4d59ab06317bfc97007a222ff866d8a76d0aa63e 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml @@ -13,6 +13,9 @@ <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> <menu_item_call label="Add Folder" diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml index ff5fdd3795322d5c3582f0b7ff7d73b3240c6d29..28c74a3d5d1813b75f8966bb9e51e2b9bfe0b95e 100644 --- a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml +++ b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml @@ -48,6 +48,9 @@ <on_click function="Places.LandmarksGear.Add.Action" parameter="add_landmark" /> + <on_enable + function="Places.LandmarksGear.Enable" + parameter="add_landmark" /> </menu_item_call> <menu_item_call label="Add Folder" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 04b5d808ecb01947993e21fc097eccf693d5c465..1e1e4722a7afd2c23524db18099c21159fe73670 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -508,6 +508,8 @@ name="Place Profile"> <menu_item_call.on_click function="World.PlaceProfile" /> + <menu_item_call.on_enable + function="World.EnablePlaceProfile" /> </menu_item_call> <menu_item_call label="About land" @@ -515,6 +517,9 @@ <menu_item_call.on_click function="Floater.Show" parameter="about_land" /> + <menu_item_call.on_enable + function="Floater.CanShow" + parameter="about_land" /> </menu_item_call> <menu_item_call label="Region / Estate" @@ -522,6 +527,9 @@ <menu_item_call.on_click function="Floater.Show" parameter="region_info" /> + <menu_item_call.on_enable + function="Floater.CanShow" + parameter="region_info" /> </menu_item_call> <menu_item_call label="My land holdings..." @@ -654,6 +662,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="sunrise" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_check label="Midday" @@ -665,6 +676,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="noon" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_check label="Sunset" @@ -676,6 +690,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="sunset" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_check label="Midnight" @@ -686,6 +703,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="midnight" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> <menu_item_separator/> <menu_item_check @@ -697,6 +717,9 @@ <menu_item_check.on_check function="World.EnableEnvSettings" parameter="region" /> + <menu_item_check.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_check> </menu> @@ -713,6 +736,9 @@ <menu_item_call.on_click function="World.EnvSettings" parameter="editor"/> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_call> <menu_item_separator/> @@ -726,6 +752,9 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="new_water"/> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> </menu_item_call> <menu_item_call label="Edit preset..." @@ -733,7 +762,10 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="edit_water"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Delete preset..." name="delete_water_preset"> @@ -755,14 +787,20 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="new_sky"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Edit preset..." name="edit_sky_preset"> <menu_item_call.on_click function="World.EnvPreset" parameter="edit_sky"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Delete preset..." name="delete_sky_preset"> @@ -784,14 +822,20 @@ <menu_item_call.on_click function="World.EnvPreset" parameter="new_day_cycle"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Edit preset..." name="edit_day_preset"> <menu_item_call.on_click function="World.EnvPreset" parameter="edit_day_cycle"/> - </menu_item_call> + <menu_item_call.on_enable + function="RLV.EnableIfNot" + parameter="setenv" /> + </menu_item_call> <menu_item_call label="Delete preset..." name="delete_day_preset"> @@ -1474,6 +1518,215 @@ parameter="sl_about" /> </menu_item_call> </menu> + <menu + create_jump_keys="true" + label="RLVa" + name="RLVa Main" + tear_off="true" + visible="true"> + <menu + label="Develop" + name="Debug" + tear_off="true"> + <menu_item_check + label="Show Top-level RLVa Menu" + name="Show Top-level RLVa Menu"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaTopLevelMenu" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaTopLevelMenu" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Show Debug Messages" + name="Show Debug Messages"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveDebug" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveDebug" /> + </menu_item_check> + <menu_item_check + label="Hide Unset or Duplicate Messages" + name="Hide Unset or Duplicate Messages"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaDebugHideUnsetDuplicate" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaDebugHideUnsetDuplicate" /> + </menu_item_check> + <menu_item_check + label="Show Assertion Failures" + name="Show Assertion Failures"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaShowAssertionFailures" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaShowAssertionFailures" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Hide Locked Layers" + name="Hide Locked Layers"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaHideLockedLayers" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaHideLockedLayers" /> + </menu_item_check> + <menu_item_check + label="Hide Locked Attachments" + name="Hide Locked Attachments"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaHideLockedAttachments" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaHideLockedAttachments" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Enable Legacy Naming" + name="Enable Legacy Naming"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaEnableLegacyNaming" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaEnableLegacyNaming" /> + </menu_item_check> + <menu_item_check + label="Enable Shared Wear" + name="Enable Shared Wear"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaEnableSharedWear" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaEnableSharedWear" /> + </menu_item_check> + <menu_item_check + label="Rename Shared Items on Wear" + name="Rename Shared Items on Wear"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaSharedInvAutoRename" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaSharedInvAutoRename" /> + </menu_item_check> + <menu_item_separator/> + <menu_item_check + label="Locks..." + name="Locks"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_locks" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_locks" /> + </menu_item_check> + </menu> + <menu_item_separator/> + <menu_item_check + label="Allow OOC Chat" + name="Allow OOC Chat"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveCanOOC" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveCanOOC" /> + </menu_item_check> + <menu_item_check + label="Show Filtered Chat" + name="Show Filtered Chat"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveShowEllipsis" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveShowEllipsis" /> + </menu_item_check> + <menu_item_check + label="Split Long Redirected Chat" + name="Split Long Redirected Chat"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaSplitRedirectChat" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaSplitRedirectChat" /> + </menu_item_check> + <menu_item_separator /> + <menu_item_check + label="Allow Temporary Attachments" + name="Allow Temporary Attachments"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaEnableTemporaryAttachments" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaEnableTemporaryAttachments" /> + </menu_item_check> + <menu_item_check + label="Forbid Give to #RLV" + name="Forbid Give to #RLV"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLoveForbidGiveToRLV" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLoveForbidGiveToRLV" /> + </menu_item_check> + <menu_item_check + label="Wear Replaces Unlocked" + name="Wear Replaces Unlocked"> + <menu_item_check.on_check + function="CheckControl" + parameter="RLVaWearReplaceUnlocked" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RLVaWearReplaceUnlocked" /> + </menu_item_check> + <menu_item_separator /> + <menu_item_check + label="Console..." + name="Console"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_console" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_console" /> + </menu_item_check> + <menu_item_check + label="Restrictions..." + name="Restrictions"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_behaviours" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_behaviours" /> + </menu_item_check> + <menu_item_check + label="Strings..." + name="Strings"> + <menu_item_check.on_check + function="Floater.Visible" + parameter="rlv_strings" /> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="rlv_strings" /> + </menu_item_check> + </menu> <menu create_jump_keys="true" label="Advanced" @@ -1487,6 +1740,12 @@ <menu_item_call.on_click function="Advanced.RebakeTextures" /> </menu_item_call> + <menu_item_call + label="Refresh Attachments" + name="Refresh Attachments"> + <menu_item_call.on_click + function="Advanced.RefreshAttachments" /> + </menu_item_call> <menu_item_call label="Set UI Size to Default" name="Set UI Size to Default" shortcut="control|alt|shift|R"> @@ -1933,6 +2192,11 @@ parameter="flexible" /> </menu_item_check> </menu> + <menu + label="RLVa" + name="RLVa Embedded" + tear_off="true" + visible="true" /> <menu_item_check label="Use Plugin Read Thread" name="Use Plugin Read Thread"> @@ -2089,7 +2353,18 @@ </menu> <!--Shortcuts--> <menu_item_separator/> - + <menu_item_check + label="RestrainedLove API" + name="RLV API"> + <menu_item_check.on_check + function="CheckControl" + parameter="RestrainedLove" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RestrainedLove" /> + <menu_item_check.on_visible + function="RLV.MainToggleVisible" /> + </menu_item_check> <menu_item_call label="Show Debug Settings" name="Debug Settings"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index e3776cdc1a4a5b294da06fdd6b2fe512971f3929..9ce1090b996a713ecf09b7fc0a4d01fd456d623c 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6455,6 +6455,14 @@ The string [STRING_NAME] is missing from strings.xml [MESSAGE] </notification> + <notification + icon="notifytip.tga" + name="ChatSystemMessageTip" + log_to_chat="true" + type="notifytip"> +[MESSAGE] + </notification> + <notification icon="notifytip.tga" name="IMSystemMessageTip" @@ -7411,6 +7419,7 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th <notification icon="notify.tga" name="UserGiveItem" + label="Inventory offer from [NAME_LABEL]" log_to_im ="true" type="offer" sound="UISndNewIncomingIMSession"> @@ -7468,6 +7477,7 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th <notification icon="notify.tga" name="TeleportOffered" + label="Teleport offer from [NAME_LABEL]" log_to_im="true" log_to_chat="false" fade_toast="false" @@ -7587,6 +7597,7 @@ Offer a teleport? <notification icon="notify.tga" name="OfferFriendship" + label="Friendship offer from [NAME_LABEL]" log_to_im="true" type="offer"> <tag>friendship</tag> @@ -7620,6 +7631,7 @@ Offer a teleport? <notification icon="notify.tga" name="OfferFriendshipNoMessage" + label="Friendship offer from [NAME_LABEL]" persist="true" type="notify"> <tag>friendship</tag> @@ -11280,7 +11292,41 @@ An internal error prevented us from properly updating your viewer. The L$ balan <tag>fail</tag> Cannot create large prims that intersect other residents. Please re-try when other residents have moved. </notification> - + + <notification + icon="alertmodal.tga" + name="RLVaChangeStrings" + type="alertmodal"> +Changes won't take effect until after you restart [APP_NAME]. + </notification> + + <notification + icon="notify.tga" + name="RLVaListRequested" + label="Restriction request from [NAME_LABEL]" + log_to_im="true" + log_to_chat="false" + type="offer"> +[NAME_SLURL] has requested to be sent a list of your currently active RLV restrictions. + <tag>confirm</tag> + <form name="form"> + <button + index="0" + default="true" + name="Allow" + text="Allow"/> + <button + index="1" + name="Always Allow" + text="Always Allow"/> + <button + index="2" + name="Deny" + text="Deny"/> + <ignore text="Confirm before sending anyone a list of my current RLV restrictions."/> + </form> + </notification> + <notification icon="alertmodal.tga" name="PreferenceChatClearLog" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index a47121ae995f848269bd4ae29c3c105aaaf4e33a..d826a31cde3e12c930a9bc12d7d2e26d8787023a 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -184,6 +184,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M layout="topleft" min_dim="100" mouse_opaque="false" + name="Net Map Panel" user_resize="true" visibility_control="NearbyListShowMap" width="313"> diff --git a/indra/newview/skins/default/xui/en/panel_rlv_locks.xml b/indra/newview/skins/default/xui/en/panel_rlv_locks.xml new file mode 100644 index 0000000000000000000000000000000000000000..80373af1f4a3fd262ecd9ad5ddac0590c8be4ef7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_rlv_locks.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + follows="all" + height="200" + label="ACTIVE RLV LOCKS" + layout="topleft" + name="panel_rlvLocks" + top="0" + width="500"> + <scroll_list + draw_border="false" + draw_heading="true" + draw_stripes="true" + follows="all" + height="167" + layout="topleft" + multi_select="false" + name="lock_list" + top_pad="0" > + <scroll_list.columns label="Lock Type" name="lock_type" width="100" /> + <scroll_list.columns label="Method" name="lock_addrem" width="60" /> + <scroll_list.columns label="Target Object / Point" name="lock_target" /> + <scroll_list.columns label="Lock Origin" name="lock_origin" width="150" /> + </scroll_list> + <panel + background_visible="false" + follows="left|right|bottom" + height="25" + label="bottom_panel" + layout="topleft" + name="bottom_panel" + top_pad="0" > + <button + image_hover_unselected="Toolbar_Left_Over" + image_overlay="Refresh_Off" + image_overlay_alignment="left" + image_selected="Toolbar_Left_Selected" + image_unselected="Toolbar_Left_Off" + label="Refresh" + left="0" + name="refresh_btn" + top="1" + width="90" /> + <icon + follows="left|right" + image_name="Toolbar_Right_Off" + left_pad="1" + name="dummy_icon" + top="1" + right="-1"/> + </panel> +</panel> \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/rlva_strings.xml b/indra/newview/skins/default/xui/en/rlva_strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..edd2c2fecd61a43f70b14807be6813324d8ec90e --- /dev/null +++ b/indra/newview/skins/default/xui/en/rlva_strings.xml @@ -0,0 +1,229 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<llsd> +<map> + + <key>strings</key> + <map> + <!-- Primarily used when @showloc restricted --> + <key>hidden_generic</key> + <map> + <key>value</key> + <string>(Hidden)</string> + </map> + <key>hidden_parcel</key> + <map> + <key>value</key> + <string>(Hidden parcel)</string> + </map> + <key>hidden_region</key> + <map> + <key>value</key> + <string>(Hidden region)</string> + </map> + + <!-- Received/sent IMs will be replaced by the matching string when @recvim/sendim restricted --> + <key>blocked_recvim</key> + <map> + <key>value</key> + <string>*** IM blocked by your viewer</string> + <key>description</key> + <string>Shown in place of the original message when an incoming IM is blocked</string> + <key>label</key> + <string>Blocked incoming IM message (local)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + <key>blocked_sendim</key> + <map> + <key>value</key> + <string>*** IM blocked by sender's viewer</string> + <key>description</key> + <string>Shown (and sent to the remote party) when an outgoing IM is blocked</string> + <key>label</key> + <string>Blocked outgoing IM message (local + remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + + <!-- Sent to the remote party when they issue @list or @except as an IM query (if enabled) --> + <key>imquery_list_deny</key> + <map> + <key>value</key> + <string>*** The other party respectfully requests you mind your own business (bunnies made me do it!)</string> + <key>description</key> + <string>Sent to the remote party when you deny their request to list your active RLV restrictions)</string> + <key>label</key> + <string>@list and @except command (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + + <!-- Sent to the remote party as a suffix to @list to inform them there might be more information --> + <key>imquery_list_suffix</key> + <map> + <key>value</key> + <string>(Use @except to see the list of active exceptions)</string> + <key>description</key> + <string>Sent to the remote party as a suffix to @list to inform them how to request your exceptions</string> + <key>label</key> + <string>@list command suffix (remote)</string> + <key>customizable</key> + <boolean>0</boolean> + </map> + + <!-- Sent to the remote party when they issue @stopim as an IM query (if enabled) --> + <key>stopim_nosession</key> + <map> + <key>value</key> + <string>*** The other party is not under a @startim restriction</string> + <key>description</key> + <string>Sent to the remote party when they attempt to forcefully close your IM conversation with them (and no such session exists)</string> + <key>label</key> + <string>@stopim command with no session (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + <key>stopim_endsession_remote</key> + <map> + <key>value</key> + <string>*** Session has been ended for the other party</string> + <key>description</key> + <string>Sent to the remote party when they attempt to forcefully close the IM conversation (and it exists)</string> + <key>label</key> + <string>@stopim command with an active session (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + <key>stopim_endsession_local</key> + <map> + <key>value</key> + <string>[NAME] has remotely closed the IM conversation with @stopim</string> + </map> + + <!-- Shown as notifications --> + <key>blocked_autopilot</key> + <map> + <key>value</key> + <string>Unable to use the autopilot due to RLV restrictions</string> + </map> + <key>blocked_generic</key> + <map> + <key>value</key> + <string>Unable to perform action due to RLV restrictions</string> + </map> + <key>blocked_groupchange</key> + <map> + <key>value</key> + <string>Unable to change your active group due to an RLV restriction; switching back to "[GROUP_SLURL]"</string> + </map> + <key>blocked_invfolder</key> + <map> + <key>value</key> + <string>Unable to perform the requested inventory action due to an RLV locked folder.</string> + </map> + <key>blocked_nearby</key> + <map> + <key>value</key> + <string>Unable to see the presence of nearby avatars due to RLV restrictions</string> + </map> + <key>blocked_permattach</key> + <map> + <key>value</key> + <string>Attempt to attach '[OBJECT]' was denied due to RLV restrictions</string> + </map> + <key>blocked_permteleport</key> + <map> + <key>value</key> + <string>'[OBJECT]' was denied permission to teleport you due to RLV restrictions</string> + </map> + <key>blocked_startim</key> + <map> + <key>value</key> + <string>Unable to start IM session with [RECIPIENT] due to RLV restrictions</string> + </map> + <key>blocked_startconf</key> + <map> + <key>value</key> + <string>Unable to start conference with [RECIPIENT] due to RLV restrictions</string> + </map> + <key>blocked_teleport</key> + <map> + <key>value</key> + <string>Unable to initiate teleport due to RLV restrictions</string> + </map> + <key>blocked_teleport_offer</key> + <map> + <key>value</key> + <string>Unable to offer teleport due to RLV restrictions</string> + </map> + <key>blocked_viewxxx</key> + <map> + <key>value</key> + <string>Unable to open [TYPE] due to RLV restrictions</string> + </map> + <key>blocked_wireframe</key> + <map> + <key>value</key> + <string>Unable to enable wireframe mode due to RLV restrictions</string> + </map> + + <!-- Sent as "Busy" messages to the remote party --> + <key>blocked_recvim_remote</key> + <map> + <key>value</key> + <string>The Resident you messaged is currently prevented from reading your instant messages at the moment, please try again later.</string> + <key>description</key> + <string>Sent to the remote party when their IM was blocked</string> + <key>label</key> + <string>Blocked incoming IM message (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + <key>blocked_tplurerequest_remote</key> + <map> + <key>value</key> + <string>The Resident is currently prevented from accepting. Please try again later.</string> + <key>description</key> + <string>Sent to the remote party when their teleport offer or request was blocked</string> + <key>label</key> + <string>Blocked teleport offer/request (remote)</string> + <key>customizable</key> + <boolean>1</boolean> + </map> + </map> + + <!-- Generic names used to replace resident names when @shownames restricted --> + <key>anonyms</key> + <array> + <string>A resident</string> + <string>This resident</string> + <string>That resident</string> + <string>An individual</string> + <string>This individual</string> + <string>That individual</string> + <string>A person</string> + <string>This person</string> + <string>That person</string> + <string>A stranger</string> + <string>This stranger</string> + <string>That stranger</string> + <string>A being</string> + <string>This being</string> + <string>That being</string> + <string>An agent</string> + <string>This agent</string> + <string>That agent</string> + <string>A soul</string> + <string>This soul</string> + <string>That soul</string> + <string>Somebody</string> + <string>Some people</string> + <string>Someone</string> + <string>Mysterious one</string> + <string>An unknown being</string> + <string>Unidentified one</string> + <string>An unknown person</string> + </array> + +</map> +</llsd> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index e1aff135a567ff7d9c93fece99a16c23879cc032..70087b5ed2b1c87b1a0784b04efcb0fe9add6db4 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -32,6 +32,11 @@ You are at [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_L SLURL: <nolink>[SLURL]</nolink> (global coordinates [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1]) [SERVER_VERSION] +[SERVER_RELEASE_NOTES_URL] + </string> + <string name="AboutPositionRLVShowLoc"> +You are in [REGION] +[SERVER_VERSION] [SERVER_RELEASE_NOTES_URL] </string> <!-- *NOTE: Do not translate text like GPU, Graphics Card, etc - @@ -62,6 +67,7 @@ VFS (cache) creation time: [VFS_TIME] HiDPI display mode: [HIDPI] </string> <string name="AboutLibs"> +RestrainedLove API: [RLV_VERSION] J2C Decoder Version: [J2C_VERSION] Audio Driver Version: [AUDIO_DRIVER_VERSION] [LIBCEF_VERSION] @@ -3638,6 +3644,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="inventory_folder_offered-im"> Inventory folder '[ITEM_NAME]' offered </string> + <string name="inventory_item_offered_rlv"> + Inventory item offered to [NAME] + </string> <string name="share_alert"> Drag items from inventory here </string> @@ -4150,6 +4159,13 @@ Try enclosing path to the editor with double quotes. <!-- Spell check settings floater --> <string name="UserDictionary">[User]</string> + <!-- RLVa --> + <string name="RLVaPendingRestart">(pending restart)</string> + <string name="RLVaToggleMessageLogin">RLVa has been [STATE] (no restart required)</string> + <string name="RLVaToggleMessageRestart">RLVa will be [STATE] after you restart</string> + <string name="RLVaToggleEnabled">enabled</string> + <string name="RLVaToggleDisabled">disabled</string> + <!-- Experience Tools strings --> <string name="experience_tools_experience">Experience</string> <string name="ExperienceNameNull">(no experience)</string> diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp index eabf9228755f11f8ed37362f0af17a250723ee28..5fd61c5a8913ac7ee84b0bbc7aba05a7ebb8957d 100644 --- a/indra/newview/tests/llslurl_test.cpp +++ b/indra/newview/tests/llslurl_test.cpp @@ -54,6 +54,34 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil:: return std::string(); } +// [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.2a) | Added: RLVa-1.2.2a +// Stub implementation to get the test to compile properly +#include "../rlvhandler.h" + +const std::string& RlvStrings::getString(const std::string& strStringName) +{ + static const std::string strMissing = "(Missing RLVa string)"; + return strMissing; +} + +bool RlvUtil::isNearbyRegion(const std::string& strRegion) +{ + return false; +} + +RlvHandler::RlvHandler() : m_pGCTimer(NULL), m_pWLSnapshot(NULL) +{ + // Array auto-initialization to 0 is non-standard? (Compiler warning in VC-8.0) + memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT); +} + +RlvHandler::~RlvHandler() +{ +} + +RlvHandler gRlvHandler; +// [/RLVa:KB] + //---------------------------------------------------------------------------- // Mock objects for the dependencies of the code we're testing