Ansariel 2025-07-09 22:50:15 +02:00
commit 7d03d5af2a
226 changed files with 3784 additions and 1631 deletions

View File

@ -308,7 +308,17 @@ jobs:
if: ${{ matrix.variant == 'avx' }}
shell: bash
run: echo "EXTRA_ARGS=${{ env.EXTRA_ARGS }} --avx2" >> $GITHUB_ENV
- name: Add custom UA string if provided
env:
FS_PF_UA: ${{ secrets.FS_PF_UA }}
run: |
if [ -n "${FS_PF_UA}" ]; then
echo "EXTRA_ARGS=${{ env.EXTRA_ARGS }} -DFS_PF_USER_AGENT=\"${FS_PF_UA}\"" >> $GITHUB_ENV
echo "Building with custom user-agent string."
else
echo "No custom user-agent string provided."
fi
shell: bash
- name: Clean up packages to give more space
run: rm *${{ env.fallback_platform }}*bz2
shell: bash
@ -369,13 +379,13 @@ jobs:
- name: Install Microsoft.Trusted.Signing.Client
if: runner.os == 'Windows'
run: |
.\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.53 -OutputDirectory .
.\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.86 -OutputDirectory .
shell: pwsh
- name: Locate Azure.CodeSigning.Dlib.dll
if: runner.os == 'Windows'
run: |
$dllPath = (Get-ChildItem ".\Microsoft.Trusted.Signing.Client.1.0.53\bin\x64\Azure.CodeSigning.Dlib.dll" -Recurse -File | Select-Object -First 1).FullName
$dllPath = (Get-ChildItem ".\Microsoft.Trusted.Signing.Client.1.0.86\bin\x64\Azure.CodeSigning.Dlib.dll" -Recurse -File | Select-Object -First 1).FullName
if (-not $dllPath) {
Write-Error "Azure.CodeSigning.Dlib.dll not found."
exit 1

View File

@ -45,7 +45,7 @@ jobs:
run: pip install discord-webhook
- name: Download Build Artifacts
uses: dawidd6/action-download-artifact@v9
uses: dawidd6/action-download-artifact@v11
id: download
with:
workflow: build_viewer.yml

View File

@ -41,7 +41,7 @@ jobs:
setup_files: ${{ steps.get-files.outputs.setup_files }}
steps:
- name: Download Build Artifacts
uses: dawidd6/action-download-artifact@v9
uses: dawidd6/action-download-artifact@v11
id: download
with:
workflow: build_viewer.yml

View File

@ -71,7 +71,7 @@ jobs:
echo "build_run_number=${{ github.event.inputs.build_run_number }}" >> "$GITHUB_OUTPUT"
fi
- name: Download Build Artifacts
uses: dawidd6/action-download-artifact@v9
uses: dawidd6/action-download-artifact@v11
id: download_build_info
with:
workflow: build_viewer.yml

View File

@ -4,16 +4,16 @@ Thank you for submitting code to Firestorm; we will review it and merge or provi
We have written this guide to help you contribute code that meets our needs. It will hopefully reduce the number of iterations required before we can merge the code.
1. **Descriptive Title**:
   - Use a clear and descriptive title for the PR.
Use a clear and descriptive title for the PR.
1. **Related Issues**:
   - Reference any related issues or pull requests by including the JIRA number and description in the commit message header (e.g., `[FIRE-12345] When I click, my head falls off` or `[FIRE-12345] prevent click detaching head`).
Reference any related issues or pull requests by including the JIRA number and description in the commit message header (e.g., `[FIRE-12345] When I click, my head falls off` or `[FIRE-12345] prevent click detaching head`).
1. **Description**:
   - Provide a detailed description of the changes. Explain why the changes are necessary and what problem they solve. If a JIRA is associated with the change, there is no need to duplicate that, but we would appreciate a summary and explanation of the fix.
Provide a detailed description of the changes. Explain why the changes are necessary and what problem they solve. If a JIRA is associated with the change, there is no need to duplicate that, but we would appreciate a summary and explanation of the fix.
1. **Comment tags (important)**:
   - We use comments to preserve the original upstream (LL) code when making modifications; this allows the person merging future code updates to see both the original code from LL and any new updates and then use those to determine whether the FS-specific changes need to be updated and reviewed.
We use comments to preserve the original upstream (LL) code when making modifications; this allows the person merging future code updates to see both the original code from LL and any new updates and then use those to determine whether the FS-specific changes need to be updated and reviewed.
If you are modifying LL code, we need the LL code preserved in a comment.
For example:
@ -38,16 +38,16 @@ Would become:
If you add new code, the same rules apply, but there is nothing to comment out.
This is done so that when LL updates the original code, we can see what the original code was doing, what their changes do, and how that relates to the changes that we applied on top.
A single line change can use the shorthand `<FS:YI/>`:
A single line change can use the shorthand `</FS:YI>`:
```c++
    bool break_stuff=true;
    bool break_stuff = true;
```
Could be fixed as follows:
```c++
    bool break_stuff=false; // <FS:Beq/> [FIRE-23456] don't break stuff.
    bool break_stuff = false; // </FS:Beq> [FIRE-23456] don't break stuff.
```
The Comment tags are only required when changing code maintained upstream. If the code you are changing is in an FS-created file, RLV code, OpenSim-only code, etc., then we do not need the comments.
@ -55,9 +55,9 @@ Could be fixed as follows:
If the code you are changing is already inside an `//<FS>` comment block, then there is no need to add a new block, but do try to make sure that any comments align with the updates you make.
5. **Testing**:
   - Include details on how the changes should be tested. Describe the testing environment and any steps needed to verify the changes.
Include details on how the changes should be tested. Describe the testing environment and any steps needed to verify the changes.
1. **Documentation**:
   - If the change includes a new feature, it would be beneficial to suggest how we should update the FS Wiki pages to help users understand the feature
If the change includes a new feature, it would be beneficial to suggest how we should update the FS Wiki pages to help users understand the feature
Thank you for your contribution!

View File

@ -25,4 +25,12 @@ Build instructions for each operating system can be found using the links below
## Contribute
Help make Firestorm better! You can get involved with improvements by filing bugs and suggesting enhancements via [JIRA](https://jira.firestormviewer.org) or [creating pull requests](doc/FS_PR_GUIDELINES.md).
Help make Firestorm better! You can get involved with improvements by filing bugs and suggesting enhancements via [JIRA](https://jira.firestormviewer.org) or [creating pull requests](CONTRIBUTING.md).
## Community respect
This section is guided by the [TPV Policy](https://secondlife.com/corporate/third-party-viewers) and the [Second Life Code of Conduct](https://github.com/secondlife/viewer?tab=coc-ov-file).
Firestorm code is made available during ongoing development, with the **master** branch representing the current nightly build. Developers and self-compilers are encouraged to work on their own forks and contribute back via pull requests, as detailed in the [contributing guide](CONTRIBUTING.md).
If you intend to use our code for your own viewer beyond personal use, please only use code from official release branches (for example, `Firestorm_7.1.13`), rather than from pre-release/preview or nightly builds.

View File

@ -73,6 +73,15 @@ if(TESTBUILD AND TESTBUILDPERIOD)
endif(TESTBUILD AND TESTBUILDPERIOD)
#</FS:Ansariel>
#<FS:Beq> Support for custom Primfeed UA
option(FS_PF_USER_AGENT "Optional compiletime Primfeed useragent string" "")
if (FS_PF_USER_AGENT)
add_compile_definitions(FS_PF_USER_AGENT="${FS_PF_USER_AGENT}")
message(STATUS "Compiling with custom Primfeed user-agent: ${FS_PF_USER_AGENT}")
else (FS_PF_USER_AGENT)
message(STATUS "Compiling with standard Primfeed user-agent")
endif (FS_PF_USER_AGENT)
# </Beq>
# <FS:Ansariel> [AVX Optimization]
option(USE_AVX_OPTIMIZATION "AVX optimization support" OFF)
option(USE_AVX2_OPTIMIZATION "AVX2 optimization support" OFF)

View File

@ -46,6 +46,8 @@
#include <map>
#include <set>
#include <boost/range.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
// <FS:ND> Suppress warnings about the string fiddling
#if LL_LINUX
@ -205,6 +207,39 @@ std::string ll_stream_notation_sd(const LLSD& sd)
return stream.str();
}
// <FS:Ansariel> Create LLSD from CSV
LLSD ll_sd_from_csv(std::istream& csv, std::string_view delimiters)
{
LLSD data;
bool headerRead{ false };
std::vector<std::string> columnNames;
std::string line;
while (std::getline(csv, line))
{
std::vector<std::string> columns;
boost::split(columns, line, boost::is_any_of(delimiters));
if (!headerRead)
{
headerRead = true;
columnNames = std::move(columns);
}
else
{
LLSD rowData;
for (size_t i = 0; i < columnNames.size() && i < columns.size(); ++i)
{
rowData[columnNames.at(i)] = columns.at(i);
}
data.append(rowData);
}
}
return data;
}
// </FS:Ansariel>
//compares the structure of an LLSD to a template LLSD and stores the
//"valid" values in a 3rd LLSD. Default values pulled from the template

View File

@ -65,6 +65,9 @@ LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
LL_COMMON_API std::string ll_stream_notation_sd(const LLSD& sd);
// <FS:Ansariel> Create LLSD from CSV
LL_COMMON_API LLSD ll_sd_from_csv(std::istream& csv, std::string_view delimiters = ",");
//compares the structure of an LLSD to a template LLSD and stores the
//"valid" values in a 3rd LLSD. Default values
//are pulled from the template. Extra keys/values in the test

View File

@ -244,14 +244,4 @@ inline size_t hash_value(const LLUUID& id) noexcept
return (size_t)id.getDigest64();
}
// <FS:Ansariel> UUID hash calculation
struct FSUUIDHash
{
inline size_t operator() (const LLUUID& id) const
{
return *reinterpret_cast<const size_t*>(id.mData);
}
};
// </FS:Ansariel> UUID hash calculation
#endif // LL_LLUUID_H

View File

@ -432,7 +432,8 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode
}
if (!bFailed && (op->mReqOffset || op->mReqLength))
{
if (op->mReqOffset != op->mReplyOffset || (op->mReqLength && op->mReqLength < op->mReplyLength))
// We should only check the offset and length if we are handling a partial content request.
if (op->mStatus == HttpStatus(HTTP_PARTIAL_CONTENT) && (op->mReqOffset != op->mReplyOffset || (op->mReqLength && op->mReqLength < op->mReplyLength)))
{
std::stringstream strm;
strm << "HTTP pipelining possibly out of sync, request wanted: " << op->mReqOffset << "-";

View File

@ -361,14 +361,12 @@ LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD
new_array = q.getValue();
}
else
{ // TODO: We could expand this to inspect the type and do a deep lerp based on type.
// for now assume a heterogeneous array of reals.
{
size_t len = std::max(value.size(), other_value.size());
for (size_t i = 0; i < len; ++i)
{
new_array[i] = lerp((F32)value[i].asReal(), (F32)other_value[i].asReal(), (F32)mix);
new_array[i] = interpolateSDValue(key_name, value[i], other_value[i], defaults, mix, skip, slerps);
}
}

View File

@ -661,15 +661,15 @@ void LLSettingsSky::blend(LLSettingsBase::ptr_t &end, F64 blendf)
mHasLegacyHaze |= lerp_legacy_float(mHazeDensity, mLegacyHazeDensity, other->mHazeDensity, other->mLegacyHazeDensity, 0.7f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_float(mDistanceMultiplier, mLegacyDistanceMultiplier, other->mDistanceMultiplier, other->mLegacyDistanceMultiplier, 0.8f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_float(mDensityMultiplier, mLegacyDensityMultiplier, other->mDensityMultiplier, other->mLegacyDensityMultiplier, 0.0001f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mAmbientColor, mLegacyAmbientColor, other->mAmbientColor, other->mLegacyAmbientColor, LLColor3(0.25f, 0.25f, 0.25f), (F32)blendf); // <FS:Beq for Hecklezz/> import pending PR #4185 Fix sky ambient color not blending.
mHasLegacyHaze |= lerp_legacy_color(mBlueHorizon, mLegacyBlueHorizon, other->mBlueHorizon, other->mLegacyBlueHorizon, LLColor3(0.4954f, 0.4954f, 0.6399f), (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mBlueDensity, mLegacyBlueDensity, other->mBlueDensity, other->mLegacyBlueDensity, LLColor3(0.2447f, 0.4487f, 0.7599f), (F32)blendf);
parammapping_t defaults = other->getParameterMap();
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
mAbsorptionConfigs = interpolateSDMap(mAbsorptionConfigs, other->mAbsorptionConfigs, defaults, blendf, skip, slerps);
mMieConfigs = interpolateSDMap(mMieConfigs, other->mMieConfigs, defaults, blendf, skip, slerps);
mRayleighConfigs = interpolateSDMap(mRayleighConfigs, other->mRayleighConfigs, defaults, blendf, skip, slerps);
mAbsorptionConfigs = interpolateSDValue("absorption_config", mAbsorptionConfigs, other->mAbsorptionConfigs, defaults, blendf, skip, slerps);
mMieConfigs = interpolateSDValue("mie_config", mMieConfigs, other->mMieConfigs, defaults, blendf, skip, slerps);
mRayleighConfigs = interpolateSDValue("rayleigh_config", mRayleighConfigs, other->mRayleighConfigs, defaults, blendf, skip, slerps);
setDirtyFlag(true);
setReplaced();

View File

@ -1502,7 +1502,17 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
{
domListOfFloats& transform = t->getValue();
auto count = transform.getCount()/16;
// <FS:Beq> FIRE-34811 Crash during import due to missing inv_bind_matrices.
if (count==0)
{
LL_WARNS("DAELOader") << "Invalid rigged mesh: Missing inv_bind_matrices." << LL_ENDL;
LLSD args;
args["Message"] = "ParsingErrorEmptyInvBindInvalidModel";
mWarningsArray.append(args);
setLoadState( ERROR_PARSING );
}
// </FS:Beq>
for (size_t k = 0; k < count; ++k)
{
LLMatrix4 mat;
@ -1520,7 +1530,14 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
}
}
}
// <FS:Beq> FIRE-34811 Crash during import due to missing inv_bind_matrices.
if (model->mSkinInfo.mInvBindMatrix.empty())
{
model->mSkinInfo.mJointNames.clear();
model->mSkinInfo.mJointNums.clear();
missingSkeletonOrScene = true; // set this true as we've just wiped that data.
}
// </FS:Beq>
//Now that we've parsed the joint array, let's determine if we have a full rig
//(which means we have all the joint sthat are required for an avatar versus
//a skinned asset attached to a node in a file that contains an entire skeleton,

View File

@ -1592,7 +1592,7 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi
for (U32 i = 0; i < mJointNames.size(); ++i)
{
ret[ "joint_names" ][ i ] = mJointNames[ i ];
if (mInvBindMatrix.size() < i) break; // <FS:Beq/> FIRE-34811 Crash during import due to missing inv_bind_matrices.
for (U32 j = 0; j < 4; j++)
{
for (U32 k = 0; k < 4; k++)

View File

@ -430,6 +430,13 @@ bool LLScrollListCtrl::setMaxItemCount(S32 max_count)
return (max_count == mMaxItemCount);
}
// <FS:PP>
S32 LLScrollListCtrl::getMaxItemCount() const
{
return mMaxItemCount;
}
// </FS:PP>
S32 LLScrollListCtrl::isEmpty() const
{
return mItemList.empty();

View File

@ -213,6 +213,7 @@ public:
// returns false if unable to set the max count so low
bool setMaxItemCount(S32 max_count);
S32 getMaxItemCount() const; // <FS:PP>
bool selectByID( const LLUUID& id ); // false if item not found

View File

@ -54,7 +54,7 @@ include(jemalloc)
include(Discord)
# <FS:ND> if using ndPhysicsstub this variable will be unset, we don't need to build any stub code viewer side in that case
if( LLPHYSICSEXTENSIONS_SRC_DIR )
if (LLPHYSICSEXTENSIONS_SRC_DIR)
# </FS:ND>
if (NOT HAVOK_TPV)
@ -81,7 +81,7 @@ if (NOT HAVOK_TPV)
endif (NOT HAVOK_TPV)
# <FS:ND>
endif( LLPHYSICSEXTENSIONS_SRC_DIR )
endif (LLPHYSICSEXTENSIONS_SRC_DIR)
# </FS:ND>
set(viewer_SOURCE_FILES
@ -128,7 +128,7 @@ set(viewer_SOURCE_FILES
fsfloaternearbychat.cpp
fsfloaterpartialinventory.cpp
fsfloaterplacedetails.cpp
fsfloaterposer.cpp
fsfloaterposer.cpp
fsfloaterposestand.cpp
fsfloaterprotectedfolders.cpp
fsfloaterradar.cpp
@ -141,7 +141,7 @@ set(viewer_SOURCE_FILES
fsfloatervramusage.cpp
fsfloaterwearablefavorites.cpp
fsfloaterwhitelisthelper.cpp
fsjointpose.cpp
fsjointpose.cpp
fskeywords.cpp
fslslbridge.cpp
fslslbridgerequest.cpp
@ -163,8 +163,8 @@ set(viewer_SOURCE_FILES
fspanelradar.cpp
fsparticipantlist.cpp
fspose.cpp
fsposeranimator.cpp
fsposingmotion.cpp
fsposeranimator.cpp
fsposingmotion.cpp
fsprimfeedauth.cpp
fsradar.cpp
fsradarentry.cpp
@ -174,7 +174,7 @@ set(viewer_SOURCE_FILES
fsscriptlibrary.cpp
fsscrolllistctrl.cpp
fsslurlcommand.cpp
fsvirtualtrackpad.cpp
fsvirtualtrackpad.cpp
fsworldmapmessage.cpp
lggbeamcolormapfloater.cpp
lggbeammapfloater.cpp
@ -194,10 +194,12 @@ set(viewer_SOURCE_FILES
vjlocalmeshimportdae.cpp
gltfscenemanager.cpp
gltf/asset.cpp
gltf/accessor.cpp
gltf/primitive.cpp
gltf/animation.cpp
# <FS:Ansariel> Group GLTF files into their subfolders
#gltf/asset.cpp
#gltf/accessor.cpp
#gltf/primitive.cpp
#gltf/animation.cpp
# </FS:Ansariel> Group GLTF files into their subfolders
groupchatlistener.cpp
llaccountingcostmanager.cpp
llaisapi.cpp
@ -300,11 +302,11 @@ set(viewer_SOURCE_FILES
llflexibleobject.cpp
llfloater360capture.cpp
llfloaterabout.cpp
llfloateravatarwelcomepack.cpp
llfloaterbvhpreview.cpp
llfloateraddpaymentmethod.cpp
llfloaterauction.cpp
llfloaterautoreplacesettings.cpp
llfloateravatar.cpp
llfloateravatarpicker.cpp
llfloateravatarrendersettings.cpp
llfloateravatartextures.cpp
@ -887,6 +889,18 @@ set(viewer_SOURCE_FILES
NACLfloaterexploresounds.cpp
)
# <FS:Ansariel> Group GLTF files into their subfolders
set(viewer_GLTF_SOURCE_FILES
gltf/asset.cpp
gltf/accessor.cpp
gltf/primitive.cpp
gltf/animation.cpp
)
source_group("Source Files\\GLTF" FILES ${viewer_GLTF_SOURCE_FILES})
list(APPEND viewer_SOURCE_FILES ${viewer_GLTF_SOURCE_FILES})
# </FS:Ansariel> Group GLTF files into their subfolders
if (OPENSIM)
list(APPEND viewer_SOURCE_FILES
fsgridhandler.cpp
@ -951,7 +965,7 @@ set(viewer_HEADER_FILES
fsfloaternearbychat.h
fsfloaterpartialinventory.h
fsfloaterplacedetails.h
fsfloaterposer.h
fsfloaterposer.h
fsfloaterposestand.h
fsfloaterprotectedfolders.h
fsfloaterradar.h
@ -987,8 +1001,8 @@ set(viewer_HEADER_FILES
fspanelradar.h
fsparticipantlist.h
fspose.h
fsposeranimator.h
fsposingmotion.h
fsposeranimator.h
fsposingmotion.h
fsprimfeedauth.h
fsradar.h
fsradarentry.h
@ -999,7 +1013,7 @@ set(viewer_HEADER_FILES
fsscrolllistctrl.h
fsslurl.h
fsslurlcommand.h
fsvirtualtrackpad.h
fsvirtualtrackpad.h
fsworldmapmessage.h
lggbeamcolormapfloater.h
lggbeammapfloater.h
@ -1019,11 +1033,13 @@ set(viewer_HEADER_FILES
gltfscenemanager.h
groupchatlistener.h
gltf/asset.h
gltf/accessor.h
gltf/buffer_util.h
gltf/primitive.h
gltf/animation.h
# <FS:Ansariel> Group GLTF files into their subfolders
#gltf/asset.h
#gltf/accessor.h
#gltf/buffer_util.h
#gltf/primitive.h
#gltf/animation.h
# </FS:Ansariel> Group GLTF files into their subfolders
llaccountingcost.h
llaccountingcostmanager.h
llaisapi.h
@ -1127,11 +1143,11 @@ set(viewer_HEADER_FILES
llflexibleobject.h
llfloater360capture.h
llfloaterabout.h
llfloateravatarwelcomepack.h
llfloaterbvhpreview.h
llfloateraddpaymentmethod.h
llfloaterauction.h
llfloaterautoreplacesettings.h
llfloateravatar.h
llfloateravatarpicker.h
llfloateravatarrendersettings.h
llfloateravatartextures.h
@ -1714,6 +1730,19 @@ set(viewer_HEADER_FILES
list(APPEND viewer_SOURCE_FILES llperfstats.cpp)
list(APPEND viewer_HEADER_FILES llperfstats.h)
# <FS:Ansariel> Group GLTF files into their subfolders
set(viewer_GLTF_HEADER_FILES
gltf/asset.h
gltf/accessor.h
gltf/buffer_util.h
gltf/primitive.h
gltf/animation.h
)
source_group("Header Files\\GLTF" FILES ${viewer_GLTF_HEADER_FILES})
list(APPEND viewer_HEADER_FILES ${viewer_GLTF_HEADER_FILES})
# </FS:Ansariel> Group GLTF files into their subfolders
if (USE_BUGSPLAT)
list(APPEND viewer_SOURCE_FILES
bugsplatattributes.cpp

View File

@ -66,8 +66,8 @@ private:
bool mBlocked;
};
typedef std::unordered_map<LLUUID, NACLAntiSpamQueueEntry*, FSUUIDHash> spam_queue_entry_map_t;
typedef std::unordered_set<LLUUID, FSUUIDHash> collision_sound_set_t;
typedef std::unordered_map<LLUUID, NACLAntiSpamQueueEntry*> spam_queue_entry_map_t;
typedef std::unordered_set<LLUUID> collision_sound_set_t;
class NACLAntiSpamQueue
{

View File

@ -16,7 +16,7 @@
#include "fscommon.h"
#include "rlvhandler.h"
static const size_t num_collision_sounds = 28;
constexpr size_t num_collision_sounds = 28;
const LLUUID collision_sounds[num_collision_sounds] =
{
LLUUID("dce5fdd4-afe4-4ea1-822f-dd52cac46b08"),
@ -73,8 +73,11 @@ bool NACLFloaterExploreSounds::postBuild()
getChild<LLButton>("play_locally_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::handlePlayLocally, this));
getChild<LLButton>("look_at_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::handleLookAt, this));
getChild<LLButton>("stop_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::handleStop, this));
getChild<LLButton>("bl_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::blacklistSound, this));
getChild<LLButton>("bl_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::blacklistSound, this, FSAssetBlacklist::eBlacklistFlag::NONE));
getChild<LLButton>("stop_locally_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::handleStopLocally, this));
getChild<LLButton>("block_avatar_worn_sounds_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::blacklistSound, this, FSAssetBlacklist::eBlacklistFlag::WORN));
getChild<LLButton>("block_avatar_rezzed_sounds_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::blacklistSound, this, FSAssetBlacklist::eBlacklistFlag::REZZED));
getChild<LLButton>("block_avatar_gesture_sounds_btn")->setClickedCallback(boost::bind(&NACLFloaterExploreSounds::blacklistSound, this, FSAssetBlacklist::eBlacklistFlag::GESTURE));
mHistoryScroller = getChild<LLScrollListCtrl>("sound_list");
mHistoryScroller->setCommitCallback(boost::bind(&NACLFloaterExploreSounds::handleSelection, this));
@ -98,31 +101,26 @@ void NACLFloaterExploreSounds::handleSelection()
childSetEnabled("play_locally_btn", num_selected);
childSetEnabled("stop_btn", num_selected);
childSetEnabled("bl_btn", num_selected);
childSetEnabled("block_avatar_worn_sounds_btn", num_selected);
childSetEnabled("block_avatar_rezzed_sounds_btn", num_selected);
childSetEnabled("block_avatar_gesture_sounds_btn", num_selected);
}
LLSoundHistoryItem NACLFloaterExploreSounds::getItem(const LLUUID& itemID)
LLSoundHistoryItem NACLFloaterExploreSounds::getItem(const LLUUID& itemID) const
{
std::map<LLUUID, LLSoundHistoryItem>::iterator found = gSoundHistory.find(itemID);
if (found != gSoundHistory.end())
if (auto found = gSoundHistory.find(itemID); found != gSoundHistory.end())
{
return found->second;
}
else
{
// If log is paused, hopefully we can find it in mLastHistory
std::list<LLSoundHistoryItem>::iterator iter = mLastHistory.begin();
std::list<LLSoundHistoryItem>::iterator end = mLastHistory.end();
for ( ; iter != end; ++iter)
{
if ((*iter).mID == itemID)
{
return (*iter);
}
}
if (auto foundHistory = std::find_if(mLastHistory.begin(), mLastHistory.end(), [&](const auto& item) { return item.mID == itemID; });
foundHistory != mLastHistory.end())
return *foundHistory;
}
LLSoundHistoryItem item;
item.mID = LLUUID::null;
return item;
return {};
}
class LLSoundHistoryItemCompare
@ -175,11 +173,9 @@ bool NACLFloaterExploreSounds::tick()
}
else
{
std::map<LLUUID, LLSoundHistoryItem>::iterator map_iter = gSoundHistory.begin();
std::map<LLUUID, LLSoundHistoryItem>::iterator map_end = gSoundHistory.end();
for ( ; map_iter != map_end; ++map_iter)
for (const auto& [id, item] : gSoundHistory)
{
history.push_back((*map_iter).second);
history.emplace_back(item);
}
LLSoundHistoryItemCompare c;
history.sort(c);
@ -189,24 +185,16 @@ bool NACLFloaterExploreSounds::tick()
// Save scroll pos and selection so they can be restored
S32 scroll_pos = mHistoryScroller->getScrollPos();
uuid_vec_t selected_ids;
std::vector<LLScrollListItem*> selected_items = mHistoryScroller->getAllSelected();
std::vector<LLScrollListItem*>::iterator selection_iter = selected_items.begin();
std::vector<LLScrollListItem*>::iterator selection_end = selected_items.end();
for (; selection_iter != selection_end; ++selection_iter)
for (const auto* item : mHistoryScroller->getAllSelected())
{
selected_ids.push_back((*selection_iter)->getUUID());
selected_ids.emplace_back(item->getUUID());
}
mHistoryScroller->clearRows();
std::list<LLUUID> unique_asset_list;
std::list<LLSoundHistoryItem>::iterator iter = history.begin();
std::list<LLSoundHistoryItem>::iterator end = history.end();
for ( ; iter != end; ++iter)
std::unordered_set<LLUUID> unique_asset_list;
for (auto& item : history)
{
LLSoundHistoryItem item = (*iter);
bool is_avatar = item.mOwnerID == item.mSourceID;
if (is_avatar && !show_avatars)
{
@ -219,7 +207,7 @@ bool NACLFloaterExploreSounds::tick()
continue;
}
bool is_repeated_asset = std::find(unique_asset_list.begin(), unique_asset_list.end(), item.mAssetID) != unique_asset_list.end();
bool is_repeated_asset = unique_asset_list.contains(item.mAssetID);
if (is_repeated_asset && !show_repeated_assets)
{
continue;
@ -237,7 +225,7 @@ bool NACLFloaterExploreSounds::tick()
continue;
}
unique_asset_list.push_back(item.mAssetID);
unique_asset_list.emplace(item.mAssetID);
LLSD element;
element["id"] = item.mID;
@ -315,26 +303,17 @@ bool NACLFloaterExploreSounds::tick()
mHistoryScroller->setScrollPos(scroll_pos);
// Clean up stopped local audio source IDs
uuid_vec_t stopped_audio_src_ids;
uuid_vec_t::iterator audio_src_id_iter = mLocalPlayingAudioSourceIDs.begin();
uuid_vec_t::iterator audio_src_id_end = mLocalPlayingAudioSourceIDs.end();
for (; audio_src_id_iter != audio_src_id_end; ++audio_src_id_iter)
while (audio_src_id_iter != mLocalPlayingAudioSourceIDs.end())
{
LLUUID audio_src_id = *audio_src_id_iter;
LLAudioSource* audio_source = gAudiop->findAudioSource(audio_src_id);
if (!audio_source || audio_source->isDone())
const LLUUID& audio_src_id = *audio_src_id_iter;
if (LLAudioSource* audio_source = gAudiop->findAudioSource(audio_src_id); !audio_source || audio_source->isDone())
{
stopped_audio_src_ids.push_back(audio_src_id);
audio_src_id_iter = mLocalPlayingAudioSourceIDs.erase(audio_src_id_iter);
}
}
for (uuid_vec_t::iterator stopped_audio_src_ids_iter = stopped_audio_src_ids.begin();
stopped_audio_src_ids_iter != stopped_audio_src_ids.end(); ++stopped_audio_src_ids_iter)
{
uuid_vec_t::iterator find_iter = std::find(mLocalPlayingAudioSourceIDs.begin(), mLocalPlayingAudioSourceIDs.end(), *stopped_audio_src_ids_iter);
if (find_iter != mLocalPlayingAudioSourceIDs.end())
else
{
mLocalPlayingAudioSourceIDs.erase(find_iter);
audio_src_id_iter++;
}
}
@ -345,29 +324,26 @@ bool NACLFloaterExploreSounds::tick()
void NACLFloaterExploreSounds::handlePlayLocally()
{
std::vector<LLScrollListItem*> selection = mHistoryScroller->getAllSelected();
std::vector<LLScrollListItem*>::iterator selection_iter = selection.begin();
std::vector<LLScrollListItem*>::iterator selection_end = selection.end();
uuid_vec_t asset_list;
for ( ; selection_iter != selection_end; ++selection_iter)
std::unordered_set<LLUUID> asset_list;
for (const auto* selected_item : mHistoryScroller->getAllSelected())
{
LLSoundHistoryItem item = getItem((*selection_iter)->getValue());
LLSoundHistoryItem item = getItem(selected_item->getValue());
if (item.mID.isNull())
{
continue;
}
// Unique assets only
if (std::find(asset_list.begin(), asset_list.end(), item.mAssetID) == asset_list.end())
if (!asset_list.contains(item.mAssetID))
{
asset_list.push_back(item.mAssetID);
asset_list.emplace(item.mAssetID);
LLUUID audio_source_id = LLUUID::generateNewID();
gAudiop->triggerSound(item.mAssetID, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI, LLVector3d::zero, LLUUID::null, audio_source_id);
mLocalPlayingAudioSourceIDs.push_back(audio_source_id);
mLocalPlayingAudioSourceIDs.emplace_back(audio_source_id);
}
}
childSetEnabled("stop_locally_btn", mLocalPlayingAudioSourceIDs.size() > 0);
childSetEnabled("stop_locally_btn", !mLocalPlayingAudioSourceIDs.empty());
}
void NACLFloaterExploreSounds::handleLookAt()
@ -407,14 +383,12 @@ void NACLFloaterExploreSounds::handleLookAt()
void NACLFloaterExploreSounds::handleStop()
{
std::vector<LLScrollListItem*> selection = mHistoryScroller->getAllSelected();
for (const auto& selection_item : selection)
for (const auto& selection_item : mHistoryScroller->getAllSelected())
{
LLSoundHistoryItem item = getItem(selection_item->getValue());
if (item.mID.notNull() && item.mPlaying)
{
LLAudioSource* audio_source = gAudiop->findAudioSource(item.mSourceID);
if (audio_source)
if (LLAudioSource* audio_source = gAudiop->findAudioSource(item.mSourceID))
{
S32 type = item.mType;
audio_source->setType(LLAudioEngine::AUDIO_TYPE_UI);
@ -449,13 +423,9 @@ void NACLFloaterExploreSounds::handleStop()
void NACLFloaterExploreSounds::handleStopLocally()
{
uuid_vec_t::iterator audio_source_id_iter = mLocalPlayingAudioSourceIDs.begin();
uuid_vec_t::iterator audio_source_id_end = mLocalPlayingAudioSourceIDs.end();
for (; audio_source_id_iter != audio_source_id_end; ++audio_source_id_iter)
for (const auto& audio_source_id : mLocalPlayingAudioSourceIDs)
{
LLUUID audio_source_id = *audio_source_id_iter;
LLAudioSource* audio_source = gAudiop->findAudioSource(audio_source_id);
if (audio_source && !audio_source->isDone())
if (LLAudioSource* audio_source = gAudiop->findAudioSource(audio_source_id); audio_source && !audio_source->isDone())
{
audio_source->play(LLUUID::null);
}
@ -465,51 +435,44 @@ void NACLFloaterExploreSounds::handleStopLocally()
}
//add sound to blacklist
void NACLFloaterExploreSounds::blacklistSound()
void NACLFloaterExploreSounds::blacklistSound(FSAssetBlacklist::eBlacklistFlag flag)
{
std::vector<LLScrollListItem*> selection = mHistoryScroller->getAllSelected();
std::vector<LLScrollListItem*>::iterator selection_iter = selection.begin();
std::vector<LLScrollListItem*>::iterator selection_end = selection.end();
for ( ; selection_iter != selection_end; ++selection_iter)
for (const auto* selected_item : mHistoryScroller->getAllSelected())
{
LLSoundHistoryItem item = getItem((*selection_iter)->getValue());
LLSoundHistoryItem item = getItem(selected_item->getValue());
if (item.mID.isNull())
{
continue;
}
std::string region_name;
LLViewerRegion* cur_region = gAgent.getRegion();
if (cur_region)
if (LLViewerRegion* cur_region = gAgent.getRegion())
{
region_name = cur_region->getName();
}
blacklist_avatar_name_cache_connection_map_t::iterator it = mBlacklistAvatarNameCacheConnections.find(item.mOwnerID);
if (it != mBlacklistAvatarNameCacheConnections.end())
if (LLAvatarName av_name; LLAvatarNameCache::get(item.mOwnerID, &av_name))
{
if (it->second.connected())
{
it->second.disconnect();
}
mBlacklistAvatarNameCacheConnections.erase(it);
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(flag == FSAssetBlacklist::eBlacklistFlag::NONE ? item.mAssetID : item.mOwnerID, av_name.getCompleteName(), region_name, LLAssetType::AT_SOUND, flag);
}
else
{
// Create unique UUID here instead of avatar UUID because we might be blacklisting more than one sound of the same user
LLUUID requestId = LLUUID::generateNewID();
mBlacklistAvatarNameCacheConnections.try_emplace(requestId, LLAvatarNameCache::get(item.mOwnerID, boost::bind(&NACLFloaterExploreSounds::onBlacklistAvatarNameCacheCallback, this, requestId, _1, _2, item.mAssetID, region_name, flag)));
}
LLAvatarNameCache::callback_connection_t cb = LLAvatarNameCache::get(item.mOwnerID, boost::bind(&NACLFloaterExploreSounds::onBlacklistAvatarNameCacheCallback, this, _1, _2, item.mAssetID, region_name));
mBlacklistAvatarNameCacheConnections.insert(std::make_pair(item.mOwnerID, cb));
}
}
void NACLFloaterExploreSounds::onBlacklistAvatarNameCacheCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLUUID& asset_id, const std::string& region_name)
void NACLFloaterExploreSounds::onBlacklistAvatarNameCacheCallback(const LLUUID& request_id, const LLUUID& av_id, const LLAvatarName& av_name, const LLUUID& asset_id, const std::string& region_name, FSAssetBlacklist::eBlacklistFlag flag)
{
blacklist_avatar_name_cache_connection_map_t::iterator it = mBlacklistAvatarNameCacheConnections.find(av_id);
if (it != mBlacklistAvatarNameCacheConnections.end())
if (auto found = mBlacklistAvatarNameCacheConnections.find(request_id); found != mBlacklistAvatarNameCacheConnections.end())
{
if (it->second.connected())
if (found->second.connected())
{
it->second.disconnect();
found->second.disconnect();
}
mBlacklistAvatarNameCacheConnections.erase(it);
mBlacklistAvatarNameCacheConnections.erase(found);
}
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(asset_id, av_name.getCompleteName(), region_name, LLAssetType::AT_SOUND);
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(flag == FSAssetBlacklist::eBlacklistFlag::NONE ? asset_id : av_id, av_name.getCompleteName(), region_name, LLAssetType::AT_SOUND, flag);
}

View File

@ -9,6 +9,7 @@
#include "lleventtimer.h"
#include "llaudioengine.h"
#include "llavatarnamecache.h"
#include "fsassetblacklist.h"
class LLCheckBoxCtrl;
class LLScrollListCtrl;
@ -22,7 +23,7 @@ public:
bool tick() override;
LLSoundHistoryItem getItem(const LLUUID& itemID);
LLSoundHistoryItem getItem(const LLUUID& itemID) const;
private:
virtual ~NACLFloaterExploreSounds();
@ -31,14 +32,14 @@ private:
void handleStop();
void handleStopLocally();
void handleSelection();
void blacklistSound();
void blacklistSound(FSAssetBlacklist::eBlacklistFlag flag);
LLScrollListCtrl* mHistoryScroller;
LLCheckBoxCtrl* mCollisionSounds;
LLCheckBoxCtrl* mRepeatedAssets;
LLCheckBoxCtrl* mAvatarSounds;
LLCheckBoxCtrl* mObjectSounds;
LLCheckBoxCtrl* mPaused;
LLScrollListCtrl* mHistoryScroller{ nullptr };
LLCheckBoxCtrl* mCollisionSounds{ nullptr };
LLCheckBoxCtrl* mRepeatedAssets{ nullptr };
LLCheckBoxCtrl* mAvatarSounds{ nullptr };
LLCheckBoxCtrl* mObjectSounds{ nullptr };
LLCheckBoxCtrl* mPaused{ nullptr };
std::list<LLSoundHistoryItem> mLastHistory;
@ -47,7 +48,7 @@ private:
typedef std::map<LLUUID, boost::signals2::connection> blacklist_avatar_name_cache_connection_map_t;
blacklist_avatar_name_cache_connection_map_t mBlacklistAvatarNameCacheConnections;
void onBlacklistAvatarNameCacheCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLUUID& asset_id, const std::string& region_name);
void onBlacklistAvatarNameCacheCallback(const LLUUID& request_id, const LLUUID& av_id, const LLAvatarName& av_name, const LLUUID& asset_id, const std::string& region_name, FSAssetBlacklist::eBlacklistFlag flag);
};
#endif

View File

@ -28,11 +28,11 @@
label_ref="Command_Avatar_Label"
tooltip_ref="Command_Avatar_Tooltip"
execute_function="Floater.Toggle"
execute_parameters="avatar"
execute_parameters="avatar_welcome_pack"
is_enabled_function="GridFeatureCheck"
is_enabled_parameters="avatar_picker"
is_running_function="Floater.IsOpen"
is_running_parameters="avatar"
is_running_parameters="avatar_welcome_pack"
/>
<command name="build"
available_in_toybox="true"

View File

@ -2197,16 +2197,16 @@
<key>Value</key>
<real>16.0</real>
</map>
<key>AvatarPickerURL</key>
<key>AvatarWelcomePack</key>
<map>
<key>Comment</key>
<string>Avatar picker contents</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/avatars.html</string>
<key>Comment</key>
<string>Avatar Welcome Pack contents</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/vawp/index.html</string>
</map>
<key>AvatarRotateThresholdSlow</key>
<map>
@ -13266,6 +13266,26 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<real>0</real>
</map>
<key>FSImpostorAvatarExclude</key>
<map>
<key>Comment</key>
<string>Allows for Animesh User or Control Avatars to be excluded from using impostor rendering. Values are: (0 - None, 1 - User, 2 - Control, 3 - Both).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
<key>SanityCheckType</key>
<string>Between</string>
<key>SanityValue</key>
<array>
<integer>0</integer>
<integer>3</integer>
</array>
<key>SanityComment</key>
<string>Setting this value lower than 0 or higher than 3 has no effect.</string>
</map>
<key>RenderAvatarComplexityMode</key>
<map>
<key>Comment</key>
@ -26443,6 +26463,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>FSManipShowJointMarkers</key>
<map>
<key>Comment</key>
<string>Show small markers where the selectable joints are.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSLocalMeshApplyJointOffsets</key>
<map>
<key>Comment</key>
@ -26476,5 +26507,271 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<!-- <FS:Zi> Area Search Defaults -->
<key>FSAreaSearch_ExcludeAttachments</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Exclude attachments</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAreaSearch_ExcludeChildPrims</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Exclude child prims</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAreaSearch_ExcludeNeighborRegions</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Exclude neighbor regions</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAreaSearch_ExcludePhysical</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Exclude physical objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAreaSearch_ExcludeReflectionProbes</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Exclude reflection probes</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_ExcludeTemporary</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Exclude temporary objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSAreaSearch_FilterDistance</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Filter by distance</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_FilterForSale</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Only show objects that are for sale</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_MaximumDistance</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Maximum distance</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>999999</integer>
</map>
<key>FSAreaSearch_MaximumPrice</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Maximum price</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>999999</integer>
</map>
<key>FSAreaSearch_MinimumDistance</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Minimum distance</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_MinimumPrice</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Minimum price</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyAttachments</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only attachments</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyCopiable</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only copiable objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyCurrentParcel</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only objects in the current parcel</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyForSale</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only objects that are for sale</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyLocked</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only locked objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyMOAP</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only objects that have shared media applied</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyModifiable</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only modifiable objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyPhantom</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only phantom objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyPhysical</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only physical objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyReflectionProbes</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only reflection probes</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyTemporary</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only temporary objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAreaSearch_OnlyTransferable</key>
<map>
<key>Comment</key>
<string>Area Search Filter: Find only transferable objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<!-- </FS:Zi> Area Search Defaults -->
</map>
</llsd>

View File

@ -89,7 +89,7 @@ static std::string RLVa_hideNameIfRestricted(std::string_view name)
return RlvStrings::getAnonym(std::string(name));
}
F32 calculateObjectDistance(LLVector3d agent_pos, LLViewerObject* object)
F32 static calculateObjectDistance(LLVector3d agent_pos, LLViewerObject* object)
{
if (object->isHUDAttachment())
{
@ -107,7 +107,7 @@ public:
FSParcelChangeObserver(FSAreaSearch* area_search_floater) : mAreaSearchFloater(area_search_floater) {}
private:
/*virtual*/ void changed()
void changed() override
{
if (mAreaSearchFloater)
{
@ -139,41 +139,11 @@ public:
}
private:
LLUUID mObjectID;
LLUUID mObjectID;
};
FSAreaSearch::FSAreaSearch(const LLSD& key) :
LLFloater(key),
mActive(false),
mFilterForSale(false),
mFilterForSaleMin(0),
mFilterForSaleMax(999999),
mFilterPhysical(false),
mFilterTemporary(false),
mRegexSearch(false),
mFilterClickAction(false),
mFilterLocked(false),
mFilterPhantom(false),
mFilterAttachment(false),
mFilterMoaP(false),
mFilterReflectionProbe(false),
mFilterDistance(false),
mFilterDistanceMin(0),
mFilterDistanceMax(999999),
mFilterPermCopy(false),
mFilterPermModify(false),
mFilterPermTransfer(false),
mFilterAgentParcelOnly(false),
mBeacons(false),
mExcludeAttachment(true),
mExcludeTemporary(true),
mExcludeReflectionProbe(false),
mExcludePhysics(true),
mExcludeChildPrims(true),
mExcludeNeighborRegions(true),
mRequestQueuePause(false),
mRequestNeedsSent(false),
mRlvBehaviorCallbackConnection()
LLFloater(key)
{
gAgent.setFSAreaSearchActive(true);
gAgent.changeInterestListMode(IL_MODE_360);
@ -197,7 +167,7 @@ FSAreaSearch::~FSAreaSearch()
// Tell the Simulator not to send us everything anymore
// and revert to the regular "keyhole" frustum of interest
// list updates.
if( !LLApp::isExiting() )
if (!LLApp::isExiting())
{
gAgent.changeInterestListMode(IL_MODE_DEFAULT);
}
@ -234,8 +204,7 @@ bool FSAreaSearch::postBuild()
if (!gSavedSettings.getBOOL("FSAreaSearchAdvanced"))
{
LLPanel* advanced_tab = mTab->getPanelByName("area_search_advanced_panel");
if (advanced_tab)
if (LLPanel* advanced_tab = mTab->getPanelByName("area_search_advanced_panel"))
{
mTab->removeTabPanel(advanced_tab);
}
@ -263,7 +232,7 @@ void FSAreaSearch::draw()
{
std::vector<LLScrollListItem*> items = mPanelList->getResultList()->getAllData();
for (const auto item : items)
for (const auto* item : items)
{
if (LLViewerObject* objectp = gObjectList.findObject(item->getUUID()); objectp)
{
@ -492,7 +461,7 @@ void FSAreaSearch::findObjects()
mRequestQueuePause = false;
}
bool FSAreaSearch::isSearchableObject(LLViewerObject* objectp, LLViewerRegion* our_region)
bool FSAreaSearch::isSearchableObject(LLViewerObject* objectp, LLViewerRegion* our_region) const
{
// need to be connected to region object is in.
if (!objectp->getRegion())
@ -1140,31 +1109,30 @@ void FSAreaSearch::getNameFromUUID(const LLUUID& id, std::string& name, bool gro
if (!gCacheName->getIfThere(id, name, is_group))
{
name = unknown_name;
if (std::find(mNamesRequested.begin(), mNamesRequested.end(), id) == mNamesRequested.end())
if (!mNamesRequested.contains(id))
{
mNamesRequested.push_back(id);
boost::signals2::connection cb_connection = gCacheName->get(id, group, boost::bind(&FSAreaSearch::callbackLoadFullName, this, _1, _2));
mNameCacheConnections.insert(std::make_pair(id, cb_connection)); // mNamesRequested will do the dupe check
mNamesRequested.emplace(id);
mNameCacheConnections.try_emplace(id, gCacheName->get(id, group, boost::bind(&FSAreaSearch::callbackLoadFullName, this, _1, _2))); // mNamesRequested will do the dupe check
}
name_requested = true;
}
}
else
{
LLAvatarName av_name;
if (!LLAvatarNameCache::get(id, &av_name))
if (LLAvatarName av_name; !LLAvatarNameCache::get(id, &av_name))
{
name = unknown_name;
if (std::find(mNamesRequested.begin(), mNamesRequested.end(), id) == mNamesRequested.end())
if (!mNamesRequested.contains(id))
{
mNamesRequested.push_back(id);
boost::signals2::connection cb_connection = LLAvatarNameCache::get(id, boost::bind(&FSAreaSearch::avatarNameCacheCallback, this, _1, _2));
mNameCacheConnections.insert(std::make_pair(id, cb_connection)); // mNamesRequested will do the dupe check
mNamesRequested.emplace(id);
mNameCacheConnections.try_emplace(id, LLAvatarNameCache::get(id, boost::bind(&FSAreaSearch::avatarNameCacheCallback, this, _1, _2))); // mNamesRequested will do the dupe check
}
name_requested = true;
}
else
{
name = av_name.getCompleteName();
}
}
}
@ -1173,7 +1141,7 @@ void FSAreaSearch::avatarNameCacheCallback(const LLUUID& id, const LLAvatarName&
callbackLoadFullName(id, av_name.getCompleteName());
}
void FSAreaSearch::callbackLoadFullName(const LLUUID& id, const std::string& full_name )
void FSAreaSearch::callbackLoadFullName(const LLUUID& id, const std::string& full_name)
{
if (auto iter = mNameCacheConnections.find(id); iter != mNameCacheConnections.end())
{
@ -1368,7 +1336,7 @@ void FSAreaSearch::onCommitCheckboxRegex()
}
}
void FSAreaSearch::setFindOwnerText(std::string value)
void FSAreaSearch::setFindOwnerText(const std::string& value)
{
mPanelFind->mOwnerLineEditor->setText(value);
}
@ -1380,10 +1348,7 @@ void FSAreaSearch::setFindOwnerText(std::string value)
FSPanelAreaSearchList::FSPanelAreaSearchList(FSAreaSearch* pointer)
: LLPanel(),
mCounterText(0),
mResultList(0),
mFSAreaSearch(pointer),
mFSAreaSearchColumnConfigConnection()
mFSAreaSearch(pointer)
{
mColumnBits["distance"] = 1;
mColumnBits["name"] = 2;
@ -1497,7 +1462,7 @@ void FSPanelAreaSearchList::updateScrollList()
// Iterate over the rows in the list, deleting ones whose object has gone away.
std::vector<LLScrollListItem*> items = mResultList->getAllData();
for (const auto item : items)
for (const auto* item : items)
{
const LLUUID& row_id = item->getUUID();
LLViewerObject* objectp = gObjectList.findObject(row_id);
@ -1603,7 +1568,7 @@ void FSPanelAreaSearchList::updateName(const LLUUID& id, const std::string& name
// Iterate over the rows in the list, updating the ones with matching id.
std::vector<LLScrollListItem*> items = mResultList->getAllData();
for (const auto item : items)
for (const auto* item : items)
{
const LLUUID& row_id = item->getUUID();
FSObjectProperties& details = mFSAreaSearch->mObjectDetails[row_id];
@ -1696,7 +1661,7 @@ bool FSPanelAreaSearchList::onContextMenuItemVisibleRLV(const LLSD& userdata)
}
std::vector<LLScrollListItem*> selected = mResultList->getAllSelected();
for (const auto item : selected)
for (const auto* item : selected)
{
const LLUUID& object_id = item->getUUID();
LLViewerObject* objectp = gObjectList.findObject(object_id);
@ -1780,7 +1745,7 @@ bool FSPanelAreaSearchList::onContextMenuItemClick(const LLSD& userdata)
std::vector<LLScrollListItem*> selected = mResultList->getAllSelected();
S32 cnt = 0;
for (const auto item : selected)
for (const auto* item : selected)
{
switch (c)
{
@ -1985,7 +1950,7 @@ bool FSPanelAreaSearchList::onContextMenuItemClick(const LLSD& userdata)
LLSelectMgr::getInstance()->deselectAll();
std::vector<LLScrollListItem*> selected = mResultList->getAllSelected();
for (const auto item : selected)
for (const auto* item : selected)
{
const LLUUID& object_id = item->getUUID();
LLViewerObject* objectp = gObjectList.findObject(object_id);
@ -2063,9 +2028,8 @@ void FSPanelAreaSearchList::buyObject(FSObjectProperties& details, LLViewerObjec
{
LLSelectMgr::getInstance()->deselectAll();
LLSelectMgr::getInstance()->selectObjectAndFamily(objectp);
LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->findNode(objectp);
if (node)
if (LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->findNode(objectp))
{
node->mValid = true;
node->mPermissions->init(details.creator_id, details.owner_id, details.last_owner_id, details.group_id);
@ -2188,89 +2152,109 @@ FSPanelAreaSearchFilter::FSPanelAreaSearchFilter(FSAreaSearch* pointer)
bool FSPanelAreaSearchFilter::postBuild()
{
mCheckboxLocked = getChild<LLCheckBoxCtrl>("filter_locked");
mCheckboxLocked->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyLocked"));
mCheckboxLocked->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxPhysical = getChild<LLCheckBoxCtrl>("filter_physical");
mCheckboxPhysical->setEnabled(false);
mCheckboxPhysical->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyPhysical"));
mCheckboxPhysical->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxTemporary = getChild<LLCheckBoxCtrl>("filter_temporary");
mCheckboxTemporary->setEnabled(false);
mCheckboxTemporary->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyTemporary"));
mCheckboxTemporary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxPhantom = getChild<LLCheckBoxCtrl>("filter_phantom");
mCheckboxPhantom->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyPhantom"));
mCheckboxPhantom->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxForSale = getChild<LLCheckBoxCtrl>("filter_for_sale");
mCheckboxForSale->set(gSavedSettings.getBOOL("FSAreaSearch_FilterForSale"));
mCheckboxForSale->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxAttachment = getChild<LLCheckBoxCtrl>("filter_attachment");
mCheckboxAttachment->setEnabled(false);
mCheckboxAttachment->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyAttachments"));
mCheckboxAttachment->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mSpinForSaleMinValue= getChild<LLSpinCtrl>("min_price");
mSpinForSaleMinValue->set((F32)gSavedSettings.getS32("FSAreaSearch_MinimumPrice"));
mSpinForSaleMinValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
mSpinForSaleMaxValue= getChild<LLSpinCtrl>("max_price");
mSpinForSaleMaxValue->set((F32)gSavedSettings.getS32("FSAreaSearch_MaximumPrice"));
mSpinForSaleMaxValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
mComboClickAction = getChild<LLComboBox>("click_action");
mComboClickAction->setValue(gSavedSettings.getS32("FSAreaSearch_ClickAction"));
mComboClickAction->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCombo, this));
mCheckboxExcludeAttachment = getChild<LLCheckBoxCtrl>("exclude_attachment");
mCheckboxExcludeAttachment->set(true);
mCheckboxExcludeAttachment->set(gSavedSettings.getBOOL("FSAreaSearch_ExcludeAttachments"));
mCheckboxExcludeAttachment->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxExcludePhysics = getChild<LLCheckBoxCtrl>("exclude_physical");
mCheckboxExcludePhysics->set(true);
mCheckboxExcludePhysics->set(gSavedSettings.getBOOL("FSAreaSearch_ExcludePhysical"));
mCheckboxExcludePhysics->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxExcludetemporary = getChild<LLCheckBoxCtrl>("exclude_temporary");
mCheckboxExcludetemporary->set(true);
mCheckboxExcludetemporary->set(gSavedSettings.getBOOL("FSAreaSearch_ExcludeTemporary"));
mCheckboxExcludetemporary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxExcludeReflectionProbes = getChild<LLCheckBoxCtrl>("exclude_reflection_probes");
mCheckboxExcludeReflectionProbes->set(false);
mCheckboxExcludeReflectionProbes->set(gSavedSettings.getBOOL("FSAreaSearch_ExcludeReflectionProbes"));
mCheckboxExcludeReflectionProbes->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxExcludeChildPrim = getChild<LLCheckBoxCtrl>("exclude_childprim");
mCheckboxExcludeChildPrim->set(true);
mCheckboxExcludeChildPrim->set(gSavedSettings.getBOOL("FSAreaSearch_ExcludeChildPrims"));
mCheckboxExcludeChildPrim->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxExcludeNeighborRegions = getChild<LLCheckBoxCtrl>("exclude_neighbor_region");
mCheckboxExcludeNeighborRegions->set(true);
mCheckboxExcludeNeighborRegions->set(gSavedSettings.getBOOL("FSAreaSearch_ExcludeNeighborRegions"));
mCheckboxExcludeNeighborRegions->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mButtonApply = getChild<LLButton>("apply");
mButtonApply->setClickedCallback(boost::bind(&FSAreaSearch::onButtonClickedSearch, mFSAreaSearch));
mButtonApply = getChild<LLButton>("save_as_default");
mButtonApply->setClickedCallback(boost::bind(&FSPanelAreaSearchFilter::onButtonClickedSaveAsDefault, this));
mCheckboxDistance = getChild<LLCheckBoxCtrl>("filter_distance");
mCheckboxExcludeAttachment->set(gSavedSettings.getBOOL("FSAreaSearch_FilterDistance"));
mCheckboxDistance->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mSpinDistanceMinValue = getChild<LLSpinCtrl>("min_distance");
mCheckboxDistance->set(gSavedSettings.getS32("FSAreaSearch_MinimumDistance"));
mSpinDistanceMinValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
mSpinDistanceMaxValue= getChild<LLSpinCtrl>("max_distance");
mSpinDistanceMaxValue->set((F32)gSavedSettings.getS32("FSAreaSearch_MaximumDistance"));
mSpinDistanceMaxValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
mCheckboxMoaP = getChild<LLCheckBoxCtrl>("filter_moap");
mCheckboxMoaP->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyMOAP"));
mCheckboxMoaP->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxReflectionProbe = getChild<LLCheckBoxCtrl>("filter_reflection_probe");
mCheckboxReflectionProbe->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyReflectionProbes"));
mCheckboxReflectionProbe->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxPermCopy = getChild<LLCheckBoxCtrl>("filter_perm_copy");
mCheckboxPermCopy->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyCopiable"));
mCheckboxPermCopy->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxPermModify = getChild<LLCheckBoxCtrl>("filter_perm_modify");
mCheckboxPermModify->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyModifiable"));
mCheckboxPermModify->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxPermTransfer = getChild<LLCheckBoxCtrl>("filter_perm_transfer");
mCheckboxPermModify->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyTransferable"));
mCheckboxPermTransfer->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
mCheckboxAgentParcelOnly = getChild<LLCheckBoxCtrl>("filter_agent_parcel_only");
mCheckboxAgentParcelOnly->set(gSavedSettings.getBOOL("FSAreaSearch_OnlyCurrentParcel"));
mCheckboxAgentParcelOnly->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
onCommitCheckbox();
return LLPanel::postBuild();
}
@ -2278,8 +2262,6 @@ void FSPanelAreaSearchFilter::onCommitCheckbox()
{
mFSAreaSearch->setFilterLocked(mCheckboxLocked->get());
mFSAreaSearch->setFilterPhantom(mCheckboxPhantom->get());
mFSAreaSearch->setFilterForSale(mCheckboxForSale->get());
mFSAreaSearch->setFilterDistance(mCheckboxDistance->get());
mFSAreaSearch->setFilterMoaP(mCheckboxMoaP->get());
mFSAreaSearch->setFilterReflectionProbe(mCheckboxReflectionProbe->get());
@ -2338,6 +2320,14 @@ void FSPanelAreaSearchFilter::onCommitCheckbox()
}
mFSAreaSearch->setFilterAttachment(mCheckboxAttachment->get());
mFSAreaSearch->setFilterForSale(mCheckboxForSale->get());
mSpinForSaleMinValue->setEnabled(mCheckboxForSale->get());
mSpinForSaleMaxValue->setEnabled(mCheckboxForSale->get());
mFSAreaSearch->setFilterDistance(mCheckboxDistance->get());
mSpinDistanceMinValue->setEnabled(mCheckboxDistance->get());
mSpinDistanceMaxValue->setEnabled(mCheckboxDistance->get());
mFSAreaSearch->setExcludeChildPrims(mCheckboxExcludeChildPrim->get());
mFSAreaSearch->setExcludeNeighborRegions(mCheckboxExcludeNeighborRegions->get());
@ -2372,6 +2362,34 @@ void FSPanelAreaSearchFilter::onCommitCombo()
}
}
void FSPanelAreaSearchFilter::onButtonClickedSaveAsDefault()
{
gSavedSettings.setBOOL("FSAreaSearch_OnlyLocked", mCheckboxLocked->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyPhysical", mCheckboxPhysical->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyTemporary", mCheckboxTemporary->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyPhantom", mCheckboxPhantom->get());
gSavedSettings.setBOOL("FSAreaSearch_FilterForSale", mCheckboxForSale->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyAttachments", mCheckboxAttachment->get());
gSavedSettings.setS32("FSAreaSearch_MinimumPrice", (S32)mSpinForSaleMinValue->get());
gSavedSettings.setS32("FSAreaSearch_MaximumPrice", (S32)mSpinForSaleMaxValue->get());
gSavedSettings.setS32("FSAreaSearch_ClickAction", mComboClickAction->getValue());
gSavedSettings.setBOOL("FSAreaSearch_ExcludeAttachments", mCheckboxExcludeAttachment->get());
gSavedSettings.setBOOL("FSAreaSearch_ExcludePhysical", mCheckboxExcludePhysics->get());
gSavedSettings.setBOOL("FSAreaSearch_ExcludeTemporary", mCheckboxExcludetemporary->get());
gSavedSettings.setBOOL("FSAreaSearch_ExcludeReflectionProbes", mCheckboxExcludeReflectionProbes->get());
gSavedSettings.setBOOL("FSAreaSearch_ExcludeChildPrims", mCheckboxExcludeChildPrim->get());
gSavedSettings.setBOOL("FSAreaSearch_ExcludeNeighborRegions", mCheckboxExcludeNeighborRegions->get());
gSavedSettings.setBOOL("FSAreaSearch_FilterDistance", mCheckboxExcludeAttachment->get());
gSavedSettings.setS32("FSAreaSearch_MinimumDistance", mCheckboxDistance->get());
gSavedSettings.setS32("FSAreaSearch_MaximumDistance", (S32)mSpinDistanceMaxValue->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyMOAP", mCheckboxMoaP->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyReflectionProbes", mCheckboxReflectionProbe->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyCopiable", mCheckboxPermCopy->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyModifiable", mCheckboxPermModify->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyTransferable", mCheckboxPermModify->get());
gSavedSettings.setBOOL("FSAreaSearch_OnlyCurrentParcel", mCheckboxAgentParcelOnly->get());
}
//---------------------------------------------------------------------------
// Options tab
//---------------------------------------------------------------------------

View File

@ -58,7 +58,7 @@ class FSScrollListCtrl;
struct FSObjectProperties
{
LLUUID id;
bool listed;
bool listed{ false };
std::string name;
std::string description;
std::string touch_name;
@ -67,9 +67,13 @@ struct FSObjectProperties
LLUUID owner_id;
LLUUID group_id;
LLUUID ownership_id;
bool group_owned;
U64 creation_date;
U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask;
bool group_owned{ false };
U64 creation_date{ 0 };
U32 base_mask{ 0 };
U32 owner_mask{ 0 };
U32 group_mask{ 0 };
U32 everyone_mask{ 0 };
U32 next_owner_mask{ 0 };
LLSaleInfo sale_info;
LLCategory category;
LLUUID last_owner_id;
@ -78,9 +82,9 @@ struct FSObjectProperties
LLAggregatePermissions ag_texture_perms_owner;
LLPermissions permissions;
uuid_vec_t texture_ids;
bool name_requested;
U32 local_id;
U64 region_handle;
bool name_requested{ false };
U32 local_id{ 0 };
U64 region_handle{ 0 };
typedef enum e_object_properties_request
{
@ -89,14 +93,7 @@ struct FSObjectProperties
FINISHED,
FAILED
} EObjectPropertiesRequest;
EObjectPropertiesRequest request;
FSObjectProperties() :
request(NEED),
listed(false),
name_requested(false)
{
}
EObjectPropertiesRequest request{ NEED };
};
//---------------------------------------------------------------------
@ -110,9 +107,9 @@ public:
FSAreaSearch(const LLSD &);
virtual ~FSAreaSearch();
/*virtual*/ bool postBuild();
virtual void draw();
virtual void onOpen(const LLSD& key);
bool postBuild() override;
virtual void draw() override;
virtual void onOpen(const LLSD& key) override;
void avatarNameCacheCallback(const LLUUID& id, const LLAvatarName& av_name);
void callbackLoadFullName(const LLUUID& id, const std::string& full_name);
@ -126,8 +123,8 @@ public:
void clearSearchText();
void onButtonClickedSearch();
void onCommitCheckboxRegex();
bool isSearchableObject (LLViewerObject* objectp, LLViewerRegion* our_region);
void setFindOwnerText(std::string value);
bool isSearchableObject(LLViewerObject* objectp, LLViewerRegion* our_region) const;
void setFindOwnerText(const std::string& value);
std::map<LLUUID, FSObjectProperties> mObjectDetails;
@ -169,10 +166,10 @@ public:
void setFilterAgentParcelOnly(bool b) { mFilterAgentParcelOnly = b; }
bool isActive() { return mActive; }
bool isActive() const { return mActive; }
private:
void requestObjectProperties(const std::vector< U32 >& request_list, bool select, LLViewerRegion* regionp);
void requestObjectProperties(const std::vector<U32>& request_list, bool select, LLViewerRegion* regionp);
void matchObject(FSObjectProperties& details, LLViewerObject* objectp);
void getNameFromUUID(const LLUUID& id, std::string& name, bool group, bool& name_requested);
@ -181,15 +178,15 @@ private:
void findObjects();
void processRequestQueue();
boost::signals2::connection mRlvBehaviorCallbackConnection;
boost::signals2::connection mRlvBehaviorCallbackConnection{};
void updateRlvRestrictions(ERlvBehaviour behavior);
S32 mRequested;
bool mRefresh;
S32 mSearchableObjects;
bool mActive;
bool mRequestQueuePause;
bool mRequestNeedsSent;
S32 mRequested{ 0 };
bool mRefresh{ false };
S32 mSearchableObjects{ 0 };
bool mActive{ false };
bool mRequestQueuePause{ false };
bool mRequestNeedsSent{ false };
std::map<U64,S32> mRegionRequests;
std::string mSearchName;
@ -199,7 +196,7 @@ private:
std::string mSearchCreator;
std::string mSearchLastOwner;
bool mRegexSearch;
bool mRegexSearch{ false };
boost::regex mRegexSearchName;
boost::regex mRegexSearchDescription;
boost::regex mRegexSearchOwner;
@ -210,57 +207,57 @@ private:
LLFrameTimer mLastUpdateTimer;
LLFrameTimer mLastPropertiesReceivedTimer;
uuid_vec_t mNamesRequested;
uuid_set_t mNamesRequested;
typedef std::map<LLUUID, boost::signals2::connection> name_cache_connection_map_t;
using name_cache_connection_map_t = std::map<LLUUID, boost::signals2::connection>;
name_cache_connection_map_t mNameCacheConnections;
LLViewerRegion* mLastRegion;
LLViewerRegion* mLastRegion{ nullptr };
class FSParcelChangeObserver;
friend class FSParcelChangeObserver;
std::unique_ptr<FSParcelChangeObserver> mParcelChangedObserver;
LLTabContainer* mTab;
FSPanelAreaSearchList* mPanelList;
FSPanelAreaSearchFind* mPanelFind;
FSPanelAreaSearchFilter* mPanelFilter;
FSPanelAreaSearchOptions* mPanelOptions;
FSPanelAreaSearchAdvanced* mPanelAdvanced;
LLTabContainer* mTab{ nullptr };
FSPanelAreaSearchList* mPanelList{ nullptr };
FSPanelAreaSearchFind* mPanelFind{ nullptr };
FSPanelAreaSearchFilter* mPanelFilter{ nullptr };
FSPanelAreaSearchOptions* mPanelOptions{ nullptr };
FSPanelAreaSearchAdvanced* mPanelAdvanced{ nullptr };
bool mBeacons;
bool mBeacons{ false };
bool mExcludeAttachment;
bool mExcludeTemporary;
bool mExcludeReflectionProbe;
bool mExcludePhysics;
bool mExcludeChildPrims;
bool mExcludeNeighborRegions;
bool mExcludeAttachment{ false };
bool mExcludeTemporary{ false };
bool mExcludeReflectionProbe{ false };
bool mExcludePhysics{ false };
bool mExcludeChildPrims{ true };
bool mExcludeNeighborRegions{ true };
bool mFilterLocked;
bool mFilterPhysical;
bool mFilterTemporary;
bool mFilterPhantom;
bool mFilterAttachment;
bool mFilterMoaP;
bool mFilterReflectionProbe;
bool mFilterLocked{ false };
bool mFilterPhysical{ true };
bool mFilterTemporary{ true };
bool mFilterPhantom{ false };
bool mFilterAttachment{ false };
bool mFilterMoaP{ false };
bool mFilterReflectionProbe{ false };
bool mFilterForSale;
S32 mFilterForSaleMin;
S32 mFilterForSaleMax;
bool mFilterForSale{ false };
S32 mFilterForSaleMin{ 0 };
S32 mFilterForSaleMax{ 999999 };
bool mFilterDistance;
S32 mFilterDistanceMin;
S32 mFilterDistanceMax;
bool mFilterDistance{ false };
S32 mFilterDistanceMin{ 0 };
S32 mFilterDistanceMax{ 0 };
bool mFilterClickAction;
U8 mFilterClickActionType;
bool mFilterClickAction{ false };
U8 mFilterClickActionType{ 0 };
bool mFilterPermCopy;
bool mFilterPermModify;
bool mFilterPermTransfer;
bool mFilterPermCopy{ false };
bool mFilterPermModify{ false };
bool mFilterPermTransfer{ false };
bool mFilterAgentParcelOnly;
bool mFilterAgentParcelOnly{ false };
protected:
static void* createPanelList(void* data);
@ -286,7 +283,7 @@ public:
FSPanelAreaSearchList(FSAreaSearch* pointer);
virtual ~FSPanelAreaSearchList();
/*virtual*/ bool postBuild();
bool postBuild() override;
void setCounterText();
void setCounterText(LLStringUtil::format_map_t args);
@ -316,14 +313,14 @@ private:
LLVector3d mAgentLastPosition;
FSAreaSearch* mFSAreaSearch;
LLButton* mRefreshButton;
FSScrollListCtrl* mResultList;
LLCheckBoxCtrl* mCheckboxBeacons;
LLTextBox* mCounterText;
FSAreaSearch* mFSAreaSearch{ nullptr };
LLButton* mRefreshButton{ nullptr };
FSScrollListCtrl* mResultList{ nullptr };
LLCheckBoxCtrl* mCheckboxBeacons{ nullptr };
LLTextBox* mCounterText{ nullptr };
std::map<std::string, U32> mColumnBits;
boost::signals2::connection mFSAreaSearchColumnConfigConnection;
std::map<std::string, U32, std::less<>> mColumnBits;
boost::signals2::connection mFSAreaSearchColumnConfigConnection{};
};
@ -339,24 +336,24 @@ public:
FSPanelAreaSearchFind(FSAreaSearch* pointer);
virtual ~FSPanelAreaSearchFind() = default;
/*virtual*/ bool postBuild();
/*virtual*/ bool handleKeyHere(KEY key,MASK mask);
bool postBuild() override;
bool handleKeyHere(KEY key,MASK mask) override;
LLLineEditor* mNameLineEditor;
LLLineEditor* mDescriptionLineEditor;
LLLineEditor* mOwnerLineEditor;
LLLineEditor* mGroupLineEditor;
LLLineEditor* mCreatorLineEditor;
LLLineEditor* mLastOwnerLineEditor;
LLCheckBoxCtrl* mCheckboxRegex;
LLLineEditor* mNameLineEditor{ nullptr };
LLLineEditor* mDescriptionLineEditor{ nullptr };
LLLineEditor* mOwnerLineEditor{ nullptr };
LLLineEditor* mGroupLineEditor{ nullptr };
LLLineEditor* mCreatorLineEditor{ nullptr };
LLLineEditor* mLastOwnerLineEditor{ nullptr };
LLCheckBoxCtrl* mCheckboxRegex{ nullptr };
private:
void onButtonClickedClear();
FSAreaSearch* mFSAreaSearch;
FSAreaSearch* mFSAreaSearch{ nullptr };
LLButton* mSearchButton;
LLButton* mClearButton;
LLButton* mSearchButton{ nullptr };
LLButton* mClearButton{ nullptr };
};
@ -372,39 +369,40 @@ public:
FSPanelAreaSearchFilter(FSAreaSearch* pointer);
virtual ~FSPanelAreaSearchFilter() = default;
/*virtual*/ bool postBuild();
bool postBuild() override;
private:
void onCommitCheckbox();
void onCommitSpin();
void onCommitCombo();
void onButtonClickedSaveAsDefault();
FSAreaSearch* mFSAreaSearch;
LLCheckBoxCtrl* mCheckboxForSale;
LLCheckBoxCtrl* mCheckboxPhysical;
LLCheckBoxCtrl* mCheckboxTemporary;
LLCheckBoxCtrl* mCheckboxLocked;
LLCheckBoxCtrl* mCheckboxPhantom;
LLCheckBoxCtrl* mCheckboxMoaP;
LLCheckBoxCtrl* mCheckboxReflectionProbe;
LLCheckBoxCtrl* mCheckboxDistance;
LLSpinCtrl* mSpinDistanceMinValue;
LLSpinCtrl* mSpinDistanceMaxValue;
LLSpinCtrl* mSpinForSaleMinValue;
LLSpinCtrl* mSpinForSaleMaxValue;
LLButton* mButtonApply;
LLComboBox* mComboClickAction;
LLCheckBoxCtrl* mCheckboxAttachment;
LLCheckBoxCtrl* mCheckboxExcludeAttachment;
LLCheckBoxCtrl* mCheckboxExcludePhysics;
LLCheckBoxCtrl* mCheckboxExcludetemporary;
LLCheckBoxCtrl* mCheckboxExcludeReflectionProbes;
LLCheckBoxCtrl* mCheckboxExcludeChildPrim;
LLCheckBoxCtrl* mCheckboxExcludeNeighborRegions;
LLCheckBoxCtrl* mCheckboxPermCopy;
LLCheckBoxCtrl* mCheckboxPermModify;
LLCheckBoxCtrl* mCheckboxPermTransfer;
LLCheckBoxCtrl* mCheckboxAgentParcelOnly;
FSAreaSearch* mFSAreaSearch{ nullptr };
LLCheckBoxCtrl* mCheckboxForSale{ nullptr };
LLCheckBoxCtrl* mCheckboxPhysical{ nullptr };
LLCheckBoxCtrl* mCheckboxTemporary{ nullptr };
LLCheckBoxCtrl* mCheckboxLocked{ nullptr };
LLCheckBoxCtrl* mCheckboxPhantom{ nullptr };
LLCheckBoxCtrl* mCheckboxMoaP{ nullptr };
LLCheckBoxCtrl* mCheckboxReflectionProbe{ nullptr };
LLCheckBoxCtrl* mCheckboxDistance{ nullptr };
LLSpinCtrl* mSpinDistanceMinValue{ nullptr };
LLSpinCtrl* mSpinDistanceMaxValue{ nullptr };
LLSpinCtrl* mSpinForSaleMinValue{ nullptr };
LLSpinCtrl* mSpinForSaleMaxValue{ nullptr };
LLButton* mButtonApply{ nullptr };
LLComboBox* mComboClickAction{ nullptr };
LLCheckBoxCtrl* mCheckboxAttachment{ nullptr };
LLCheckBoxCtrl* mCheckboxExcludeAttachment{ nullptr };
LLCheckBoxCtrl* mCheckboxExcludePhysics{ nullptr };
LLCheckBoxCtrl* mCheckboxExcludetemporary{ nullptr };
LLCheckBoxCtrl* mCheckboxExcludeReflectionProbes{ nullptr };
LLCheckBoxCtrl* mCheckboxExcludeChildPrim{ nullptr };
LLCheckBoxCtrl* mCheckboxExcludeNeighborRegions{ nullptr };
LLCheckBoxCtrl* mCheckboxPermCopy{ nullptr };
LLCheckBoxCtrl* mCheckboxPermModify{ nullptr };
LLCheckBoxCtrl* mCheckboxPermTransfer{ nullptr };
LLCheckBoxCtrl* mCheckboxAgentParcelOnly{ nullptr };
};
@ -423,9 +421,9 @@ private:
void onCommitCheckboxDisplayColumn(const LLSD& userdata);
bool onEnableColumnVisibilityChecked(const LLSD& userdata);
FSAreaSearch* mFSAreaSearch;
FSAreaSearch* mFSAreaSearch{ nullptr };
std::map<std::string, LLScrollListColumn::Params> mColumnParms;
std::map<std::string, LLScrollListColumn::Params, std::less<>> mColumnParms;
};
@ -440,11 +438,11 @@ public:
FSPanelAreaSearchAdvanced() = default;
virtual ~FSPanelAreaSearchAdvanced() = default;
/*virtual*/ bool postBuild();
bool postBuild() override;
LLCheckBoxCtrl* mCheckboxClickTouch;
LLCheckBoxCtrl* mCheckboxClickBuy;
LLCheckBoxCtrl* mCheckboxClickSit;
LLCheckBoxCtrl* mCheckboxClickTouch{ nullptr };
LLCheckBoxCtrl* mCheckboxClickBuy{ nullptr };
LLCheckBoxCtrl* mCheckboxClickSit{ nullptr };
};
#endif // FS_AREASEARCH_H

View File

@ -40,7 +40,7 @@
const LLUUID MAGIC_ID("3c115e51-04f4-523c-9fa6-98aff1034730");
LLAssetType::EType S32toAssetType(S32 assetindex)
static LLAssetType::EType S32toAssetType(S32 assetindex)
{
LLAssetType::EType type;
switch (assetindex)
@ -66,39 +66,9 @@ LLAssetType::EType S32toAssetType(S32 assetindex)
return type;
}
void FSAssetBlacklist::init()
LLSD FSAssetBlacklistData::toLLSD() const
{
mBlacklistFileName = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "asset_blacklist.xml");
loadBlacklist();
}
bool FSAssetBlacklist::isBlacklisted(const LLUUID& id, LLAssetType::EType type)
{
if (mBlacklistData.empty())
{
return false;
}
blacklist_type_map_t::iterator it = mBlacklistTypeContainer.find(type);
if (it == mBlacklistTypeContainer.end())
{
return false;
}
blacklisted_uuid_container_t uuids = it->second;
return (uuids.find(id) != uuids.end());
}
void FSAssetBlacklist::addNewItemToBlacklist(const LLUUID& id, const std::string& name, const std::string& region, LLAssetType::EType type, bool permanent /*= true*/, bool save /*= true*/)
{
if (isBlacklisted(id, type))
{
return;
}
LLDate curdate = LLDate((double)time_corrected());
std::string input_date = curdate.asString();
std::string input_date = date.asString();
input_date.replace(input_date.find("T"), 1, " ");
input_date.resize(input_date.size() - 1);
@ -106,10 +76,94 @@ void FSAssetBlacklist::addNewItemToBlacklist(const LLUUID& id, const std::string
data["asset_name"] = name;
data["asset_region"] = region;
data["asset_type"] = type;
data["asset_blacklist_flag"] = flags;
data["asset_date"] = input_date;
data["asset_permanent"] = permanent;
addNewItemToBlacklistData(id, data, save);
return data;
}
FSAssetBlacklistData FSAssetBlacklistData::fromLLSD(const LLSD& data)
{
FSAssetBlacklistData blacklistdata;
std::string asset_date = data["asset_date"].asString() + "Z";
asset_date.replace(asset_date.find(" "), 1, "T");
blacklistdata.name = data["asset_name"].asString();
blacklistdata.region = data["asset_region"].asString();
blacklistdata.type = S32toAssetType(data["asset_type"].asInteger());
blacklistdata.flags = data.has("asset_blacklist_flag") ? data["asset_blacklist_flag"].asInteger() : 0;
blacklistdata.date = LLDate(asset_date);
blacklistdata.permanent = data["asset_permanent"].asBoolean();
return blacklistdata;
}
void FSAssetBlacklist::init()
{
mBlacklistFileName = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "asset_blacklist.xml");
loadBlacklist();
}
bool FSAssetBlacklist::isBlacklisted(const LLUUID& id, LLAssetType::EType type, eBlacklistFlag flag) const
{
if (mBlacklistData.empty())
{
return false;
}
if (!mBlacklistTypeContainer.contains(type))
{
return false;
}
if (!mBlacklistTypeContainer.at(type).contains(id))
{
return false;
}
const auto& data_it = mBlacklistData.find(id);
if (data_it == mBlacklistData.end())
{
return false;
}
return (data_it->second.flags == eBlacklistFlag::NONE && flag == eBlacklistFlag::NONE) || (data_it->second.flags & flag) != 0;
}
void FSAssetBlacklist::addNewItemToBlacklist(const LLUUID& id, const std::string& name, const std::string& region, LLAssetType::EType type, eBlacklistFlag flag /*= eBlacklistFlag::NONE*/, bool permanent /*= true*/, bool save /*= true*/)
{
LLDate curdate = LLDate((double)time_corrected());
std::string input_date = curdate.asString();
input_date.replace(input_date.find("T"), 1, " ");
input_date.resize(input_date.size() - 1);
FSAssetBlacklistData data;
if (auto it = mBlacklistData.find(id); it != mBlacklistData.end())
{
data = it->second;
data.name = name;
data.region = region;
data.date = LLDate((double)time_corrected());
data.permanent = permanent;
data.flags |= flag;
addNewItemToBlacklistData(id, data, save);
}
else
{
data.name = name;
data.region = region;
data.date = LLDate((double)time_corrected());
data.permanent = permanent;
data.flags = flag;
data.type = type;
addNewItemToBlacklistData(id, data, save);
}
}
bool FSAssetBlacklist::removeItem(const LLUUID& id)
@ -122,14 +176,17 @@ bool FSAssetBlacklist::removeItem(const LLUUID& id)
{
return false;
}
// Erase for each possible type
for (auto& [type, container] : mBlacklistTypeContainer)
{
container.erase(id);
}
LLSD data = it->second;
LLAssetType::EType type = S32toAssetType(data["asset_type"].asInteger());
mBlacklistTypeContainer[type].erase(id);
auto data = it->second;
mBlacklistData.erase(it);
return data["asset_permanent"].asBoolean();
return data.permanent;
}
void FSAssetBlacklist::removeItemFromBlacklist(const LLUUID& id)
@ -142,7 +199,8 @@ void FSAssetBlacklist::removeItemsFromBlacklist(const uuid_vec_t& ids)
if (!ids.empty())
{
bool need_save = false;
LLSD data;
changed_signal_data_t data;
for (const auto& id : ids)
{
@ -150,7 +208,7 @@ void FSAssetBlacklist::removeItemsFromBlacklist(const uuid_vec_t& ids)
{
need_save = true;
}
data.append(id.asString());
data.emplace_back(id, std::nullopt);
}
if (need_save)
@ -165,14 +223,43 @@ void FSAssetBlacklist::removeItemsFromBlacklist(const uuid_vec_t& ids)
}
}
void FSAssetBlacklist::addNewItemToBlacklistData(const LLUUID& id, const LLSD& data, bool save)
void FSAssetBlacklist::removeFlagsFromItem(const LLUUID& id, S32 combined_flags)
{
LLAssetType::EType type = S32toAssetType(data["asset_type"].asInteger());
auto it = mBlacklistData.find(id);
if (it == mBlacklistData.end())
{
return;
}
addEntryToBlacklistMap(id, type);
mBlacklistData[id] = data;
auto& data = it->second;
S32 current_flags = data.flags;
if (type == LLAssetType::AT_SOUND)
current_flags &= ~combined_flags;
if (current_flags == eBlacklistFlag::NONE)
{
removeItemsFromBlacklist({ id });
}
else
{
data.flags = current_flags;
addNewItemToBlacklistData(id, data, true);
}
}
void FSAssetBlacklist::addNewItemToBlacklistData(const LLUUID& id, const FSAssetBlacklistData& data, bool save)
{
if (auto it = mBlacklistData.find(id); it != mBlacklistData.end())
{
it->second = data;
}
else
{
addEntryToBlacklistMap(id, data.type);
mBlacklistData.try_emplace(id, data);
}
if (data.type == LLAssetType::AT_SOUND && data.flags == eBlacklistFlag::NONE)
{
LLFileSystem::removeFile(id, LLAssetType::AT_SOUND);
std::string wav_path = gDirUtilp->getExpandedFilename(LL_PATH_FS_SOUND_CACHE, id.asString()) + ".dsf";
@ -193,7 +280,7 @@ void FSAssetBlacklist::addNewItemToBlacklistData(const LLUUID& id, const LLSD& d
if (!mBlacklistChangedCallback.empty())
{
mBlacklistChangedCallback(LLSD().with(id.asString(), data), eBlacklistOperation::BLACKLIST_ADD);
mBlacklistChangedCallback({ {id, data} }, eBlacklistOperation::BLACKLIST_ADD);
}
}
@ -247,7 +334,7 @@ void FSAssetBlacklist::loadBlacklist()
gObjectList.addDerenderedItem(uid, true);
}
addNewItemToBlacklistData(uid, entry_data, false);
addNewItemToBlacklistData(uid, FSAssetBlacklistData::fromLLSD(entry_data), false);
}
}
}
@ -285,7 +372,7 @@ void FSAssetBlacklist::loadBlacklist()
newdata["asset_date"] = data["entry_date"].asString();
newdata["asset_permanent"] = true; // For conversion of old data
addNewItemToBlacklistData(uid, newdata, false);
addNewItemToBlacklistData(uid, FSAssetBlacklistData::fromLLSD(newdata), false);
}
}
oldfile.close();
@ -306,12 +393,12 @@ void FSAssetBlacklist::saveBlacklist()
for (const auto& [id, data] : mBlacklistData)
{
if (data["asset_permanent"].asBoolean())
if (data.permanent)
{
LLUUID shadow_id{ id };
LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
cipher.encrypt(shadow_id.mData, UUID_BYTES);
savedata[shadow_id.asString()] = data;
savedata[shadow_id.asString()] = data.toLLSD();
}
}

View File

@ -35,21 +35,45 @@
#include "llsingleton.h"
#include "llassettype.h"
using blacklisted_uuid_container_t = std::unordered_set<LLUUID, FSUUIDHash>;
struct FSAssetBlacklistData
{
std::string name;
std::string region;
LLAssetType::EType type;
S32 flags{ 0 };
LLDate date;
bool permanent{ false };
LLSD toLLSD() const;
static FSAssetBlacklistData fromLLSD(const LLSD& data);
};
using blacklisted_uuid_container_t = std::unordered_set<LLUUID>;
using blacklist_type_map_t = std::map<LLAssetType::EType, blacklisted_uuid_container_t>;
using blacklist_data_t = std::unordered_map<LLUUID, LLSD, FSUUIDHash>;
using blacklist_data_t = std::unordered_map<LLUUID, FSAssetBlacklistData>;
class FSAssetBlacklist : public LLSingleton<FSAssetBlacklist>
{
LLSINGLETON_EMPTY_CTOR(FSAssetBlacklist);
public:
enum eBlacklistFlag
{
NONE = 0,
WORN = 1 << 0,
REZZED = 1 << 1,
GESTURE = 1 << 2,
LAST_FLAG = 1 << 2
};
void init();
bool isBlacklisted(const LLUUID& id, LLAssetType::EType type);
void addNewItemToBlacklist(const LLUUID& id, const std::string& name, const std::string& region, LLAssetType::EType type, bool permanent = true, bool save = true);
void addNewItemToBlacklistData(const LLUUID& id, const LLSD& data, bool save = true);
bool isBlacklisted(const LLUUID& id, LLAssetType::EType type, eBlacklistFlag flag = eBlacklistFlag::NONE) const;
void addNewItemToBlacklist(const LLUUID& id, const std::string& name, const std::string& region, LLAssetType::EType type, eBlacklistFlag flag = eBlacklistFlag::NONE,bool permanent = true, bool save = true);
void addNewItemToBlacklistData(const LLUUID& id, const FSAssetBlacklistData& data, bool save = true);
void removeItemFromBlacklist(const LLUUID& id);
void removeItemsFromBlacklist(const uuid_vec_t& ids);
void removeFlagsFromItem(const LLUUID& id, S32 combined_flags);
void saveBlacklist();
blacklist_data_t getBlacklistData() const { return mBlacklistData; };
@ -60,7 +84,8 @@ public:
BLACKLIST_REMOVE
};
typedef boost::signals2::signal<void(const LLSD& data, eBlacklistOperation op)> blacklist_changed_callback_t;
using changed_signal_data_t = std::vector<std::pair<LLUUID, std::optional<FSAssetBlacklistData>>>;
using blacklist_changed_callback_t = boost::signals2::signal<void(const changed_signal_data_t& data, eBlacklistOperation op)>;
boost::signals2::connection setBlacklistChangedCallback(const blacklist_changed_callback_t::slot_type& cb)
{
return mBlacklistChangedCallback.connect(cb);

View File

@ -92,10 +92,10 @@ bool FSCommon::is_irc_me_prefix(std::string_view text)
std::string FSCommon::unescape_name(std::string_view name)
{
// bugfix for SL-46920: preventing filenames that break stuff.
char * curl_str = curl_unescape(name.data(), static_cast<int>(name.size())); // Calling data() should be ok here because we also pass the length
char* curl_str = curl_unescape(name.data(), static_cast<int>(name.size())); // Calling data() should be ok here because we also pass the length
std::string unescaped_name(curl_str);
curl_free(curl_str);
curl_str = NULL;
curl_str = nullptr;
return unescaped_name;
}
@ -218,11 +218,9 @@ void FSCommon::applyDefaultBuildPreferences(LLViewerObject* object)
if (gSavedPerAccountSettings.getBOOL("FSBuildPrefs_EmbedItem"))
{
LLUUID item_id(gSavedPerAccountSettings.getString("FSBuildPrefs_Item"));
if (item_id.notNull())
if (LLUUID item_id(gSavedPerAccountSettings.getString("FSBuildPrefs_Item")); item_id.notNull())
{
LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(gInventory.getObject(item_id));
if (item)
if (LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(gInventory.getObject(item_id)))
{
if (item->getType() == LLAssetType::AT_LSL_TEXT)
{
@ -297,22 +295,19 @@ bool FSCommon::isLinden(const LLUUID& av_id)
{
gCacheName->getFirstLastName(av_id, first_name, last_name);
}
#ifdef OPENSIM
if (LLGridManager::getInstance()->isInOpenSim())
{
LLViewerRegion* region = gAgent.getRegion();
if (!region) return false;
bool is_god = false;
// <FS:CR> They may not be "Lindens" per se, but opensim has gods.
std::set<std::string> gods = region->getGods();
if (!gods.empty())
{
is_god = (gods.find(first_name + " " + last_name) != gods.end()
|| gods.find(last_name) != gods.end());
}
return is_god;
if (!region)
return false;
const auto& gods = region->getGods();
return gods.contains(first_name + " " + last_name) || gods.contains(last_name);
}
#endif
return (last_name == LL_LINDEN ||
last_name == LL_MOLE ||
last_name == LL_PRODUCTENGINE ||
@ -333,105 +328,79 @@ bool FSCommon::requestGroupData(const LLUUID& groupID)
bool FSCommon::checkIsActionEnabled(const LLUUID& av_id, EFSRegistrarFunctionActionType action)
{
bool isSelf = (av_id == gAgentID);
const bool isSelf = (av_id == gAgentID);
if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_ADD_FRIEND)
switch (action)
{
return (!isSelf && !LLAvatarActions::isFriend(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_REMOVE_FRIEND)
{
return (!isSelf && LLAvatarActions::isFriend(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_SEND_IM)
{
return (!isSelf && RlvActions::canStartIM(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_VIEW_TRANSCRIPT)
{
return (!isSelf && LLLogChat::isTranscriptExist(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_ZOOM_IN)
{
return (!isSelf && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && LLAvatarActions::canZoomIn(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_OFFER_TELEPORT)
{
return (!isSelf && LLAvatarActions::canOfferTeleport(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_REQUEST_TELEPORT)
{
return (!isSelf && LLAvatarActions::canRequestTeleport(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_SHOW_PROFILE)
{
return (isSelf || !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_TRACK_AVATAR)
{
return (!isSelf && FSRadar::getInstance()->getEntry(av_id) != NULL);
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_ACT_TELEPORT_TO)
{
return (!isSelf && FSRadar::getInstance()->getEntry(av_id) != NULL);
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_AVATAR_BLOCKED)
{
return (!isSelf && LLMuteList::getInstance()->isMuted(av_id));
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_IS_SELF)
{
return isSelf;
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_IS_NOT_SELF)
{
return !isSelf;
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA)
{
return !requestGroupData(av_id);
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_HAVE_GROUP_DATA)
{
return requestGroupData(av_id);
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_CAN_LEAVE_GROUP)
{
if (gAgent.getGroupID() == av_id && !RlvActions::canChangeActiveGroup())
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_ADD_FRIEND:
return (!isSelf && !LLAvatarActions::isFriend(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_REMOVE_FRIEND:
return (!isSelf && LLAvatarActions::isFriend(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_SEND_IM:
return (!isSelf && RlvActions::canStartIM(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_VIEW_TRANSCRIPT:
return (!isSelf && LLLogChat::isTranscriptExist(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_ZOOM_IN:
return (!isSelf && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && LLAvatarActions::canZoomIn(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_OFFER_TELEPORT:
return (!isSelf && LLAvatarActions::canOfferTeleport(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_REQUEST_TELEPORT:
return (!isSelf && LLAvatarActions::canRequestTeleport(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_SHOW_PROFILE:
return (isSelf || !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_TRACK_AVATAR:
return (!isSelf && FSRadar::getInstance()->getEntry(av_id) != nullptr);
case EFSRegistrarFunctionActionType::FS_RGSTR_ACT_TELEPORT_TO:
return (!isSelf && FSRadar::getInstance()->getEntry(av_id) != nullptr);
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_AVATAR_BLOCKED:
return (!isSelf && LLMuteList::getInstance()->isMuted(av_id));
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_IS_SELF:
return isSelf;
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_IS_NOT_SELF:
return !isSelf;
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_WAITING_FOR_GROUP_DATA:
return !requestGroupData(av_id);
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_HAVE_GROUP_DATA:
return requestGroupData(av_id);
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_CAN_LEAVE_GROUP:
{
return false;
}
if (gAgent.getGroupID() == av_id && !RlvActions::canChangeActiveGroup())
{
return false;
}
return gAgent.isInGroup(av_id);
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_CAN_JOIN_GROUP)
{
if (!gAgent.canJoinGroups())
return gAgent.isInGroup(av_id);
}
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_CAN_JOIN_GROUP:
{
return false;
}
if (!gAgent.canJoinGroups())
{
return false;
}
if (!RlvActions::canChangeActiveGroup())
if (!RlvActions::canChangeActiveGroup())
{
return false;
}
LLGroupMgrGroupData* groupData = LLGroupMgr::getInstance()->getGroupData(av_id);
if (!groupData || !groupData->mOpenEnrollment)
{
return false;
}
return !gAgent.isInGroup(av_id);
}
case EFSRegistrarFunctionActionType::FS_RGSTR_CHK_GROUP_NOT_ACTIVE:
{
return false;
}
if (!RlvActions::canChangeActiveGroup())
{
return false;
}
LLGroupMgrGroupData* groupData = LLGroupMgr::getInstance()->getGroupData(av_id);
if (!groupData || !groupData->mOpenEnrollment)
{
return false;
return (gAgent.isInGroup(av_id) && gAgent.getGroupID() != av_id);
}
return !gAgent.isInGroup(av_id);
}
else if (action == EFSRegistrarFunctionActionType::FS_RGSTR_CHK_GROUP_NOT_ACTIVE)
{
if (!RlvActions::canChangeActiveGroup())
{
return false;
}
return (gAgent.isInGroup(av_id) && gAgent.getGroupID() != av_id);
default:;
}
return false;
@ -453,7 +422,7 @@ std::string FSCommon::getAvatarNameByDisplaySettings(const LLAvatarName& av_name
std::string name;
static LLCachedControl<bool> NameTagShowUsernames(gSavedSettings, "NameTagShowUsernames");
static LLCachedControl<bool> UseDisplayNames(gSavedSettings, "UseDisplayNames");
if ((NameTagShowUsernames) && (UseDisplayNames))
if (NameTagShowUsernames && UseDisplayNames)
{
name = av_name.getCompleteName();
}
@ -494,21 +463,21 @@ bool FSCommon::isDefaultTexture(const LLUUID& asset_id)
bool FSCommon::isLegacySkin()
{
std::string current_skin = gSavedSettings.getString("FSInternalSkinCurrent");
return (current_skin == "Vintage");
static bool is_legacy_skin = gSavedSettings.getString("FSInternalSkinCurrent") == "Vintage";
return is_legacy_skin;
}
bool FSCommon::isFilterEditorKeyCombo(KEY key, MASK mask)
{
return (mask == MASK_CONTROL && key == 'F' && gSavedSettings.getBOOL("FSSelectLocalSearchEditorOnShortcut"));
static LLCachedControl<bool> select_search_on_shortcut(gSavedSettings, "FSSelectLocalSearchEditorOnShortcut");
return (mask == MASK_CONTROL && key == 'F' && select_search_on_shortcut);
}
LLUUID FSCommon::getGroupForRezzing()
{
LLUUID group_id{ gAgent.getGroupID() };
LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
if (parcel && gSavedSettings.getBOOL("RezUnderLandGroup"))
if (LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); parcel && gSavedSettings.getBOOL("RezUnderLandGroup"))
{
// In both cases, group-owned or not, the group ID is the same;
// No need to query the parcel owner ID as it will be either

View File

@ -513,7 +513,7 @@ void FSData::processAssets(const LLSD& assets)
{
continue;
}
FSAssetBlacklist::instance().addNewItemToBlacklistData(uid, data, false);
FSAssetBlacklist::instance().addNewItemToBlacklistData(uid, FSAssetBlacklistData::fromLLSD(data), false);
LL_DEBUGS("fsdata") << "Added " << uid << " to assets list." << LL_ENDL;
}
}
@ -881,23 +881,27 @@ void FSData::addAgents()
return;
}
for (std::map<LLUUID, S32>::iterator iter = mTeamAgents.begin(); iter != mTeamAgents.end(); ++iter)
for (const auto& [id, flags] : mTeamAgents)
{
if (iter->second & NO_SPAM)
if (flags & NO_SPAM)
{
LLUUID id = iter->first;
avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id);
if (it != mAvatarNameCacheConnections.end())
if (LLAvatarName av_name; LLAvatarNameCache::get(id, &av_name))
{
if (it->second.connected())
{
it->second.disconnect();
}
mAvatarNameCacheConnections.erase(it);
onNameCache(id, av_name);
}
else
{
if (auto it = mAvatarNameCacheConnections.find(id); it != mAvatarNameCacheConnections.end())
{
if (it->second.connected())
{
it->second.disconnect();
}
mAvatarNameCacheConnections.erase(it);
}
LLAvatarNameCache::callback_connection_t cb = LLAvatarNameCache::get(id, boost::bind(&FSData::onNameCache, this, _1, _2));
mAvatarNameCacheConnections.insert(std::make_pair(id, cb));
mAvatarNameCacheConnections.try_emplace(id, LLAvatarNameCache::get(id, boost::bind(&FSData::onNameCache, this, _1, _2)));
}
}
}
}

View File

@ -90,25 +90,51 @@ void FSFloaterAssetBlacklist::onOpen(const LLSD& key)
buildBlacklist();
}
std::string FSFloaterAssetBlacklist::getTypeString(S32 type)
FSAssetBlacklist::eBlacklistFlag FSFloaterAssetBlacklist::getFlagFromLLSD(const LLSD& data)
{
if (data.has("asset_blacklist_flag"))
{
return static_cast<FSAssetBlacklist::eBlacklistFlag>(data["asset_blacklist_flag"].asInteger());
}
return FSAssetBlacklist::eBlacklistFlag::NONE;
}
std::string FSFloaterAssetBlacklist::getTypeString(S32 type) const
{
switch (type)
{
case LLAssetType::AT_TEXTURE:
return getString("asset_texture");
case LLAssetType::AT_SOUND:
return getString("asset_sound");
case LLAssetType::AT_OBJECT:
return getString("asset_object");
case LLAssetType::AT_ANIMATION:
return getString("asset_animation");
case LLAssetType::AT_PERSON:
return getString("asset_resident");
case LLAssetType::AT_SOUND:
return getString("asset_sound");
default:
return getString("asset_unknown");
}
}
std::string FSFloaterAssetBlacklist::getFlagString(FSAssetBlacklist::eBlacklistFlag flag) const
{
switch (flag)
{
case FSAssetBlacklist::eBlacklistFlag::NONE:
return getString("blacklist_flag_none");
case FSAssetBlacklist::eBlacklistFlag::WORN:
return getString("blacklist_flag_mute_avatar_worn_objects_sounds");
case FSAssetBlacklist::eBlacklistFlag::REZZED:
return getString("blacklist_flag_mute_avatar_rezzed_objects_sounds");
case FSAssetBlacklist::eBlacklistFlag::GESTURE:
return getString("blacklist_flag_mute_avatar_gestures_sounds");
default:
return getString("blacklist_flag_unknown");
}
}
void FSFloaterAssetBlacklist::buildBlacklist()
{
bool needs_sort = mResultList->isSorted();
@ -123,70 +149,112 @@ void FSFloaterAssetBlacklist::buildBlacklist()
mResultList->updateSort();
}
void FSFloaterAssetBlacklist::addElementToList(const LLUUID& id, const LLSD& data)
void FSFloaterAssetBlacklist::addElementToList(const LLUUID& id, const FSAssetBlacklistData& data)
{
// Undo the persisted date in legacy format...
std::string asset_date = data["asset_date"].asString() + "Z";
asset_date.replace(asset_date.find(" "), 1, "T");
LLDate date(asset_date);
std::string date_str = getString("DateFormatString");
LLSD substitution;
substitution["datetime"] = date.secondsSinceEpoch();
substitution["datetime"] = data.date.secondsSinceEpoch();
LLStringUtil::format(date_str, substitution);
LLSD element;
element["id"] = id;
element["columns"][0]["column"] = "name";
element["columns"][0]["type"] = "text";
element["columns"][0]["value"] = !data["asset_name"].asString().empty() ? data["asset_name"].asString() : getString("unknown_object");
element["columns"][1]["column"] = "region";
element["columns"][1]["type"] = "text";
element["columns"][1]["value"] = !data["asset_region"].asString().empty() ? data["asset_region"].asString() : getString("unknown_region");
element["columns"][2]["column"] = "type";
element["columns"][2]["type"] = "text";
element["columns"][2]["value"] = getTypeString(data["asset_type"].asInteger());
element["columns"][3]["column"] = "date";
element["columns"][3]["type"] = "text";
element["columns"][3]["value"] = date_str;
element["columns"][4]["column"] = "permanent";
element["columns"][4]["type"] = "text";
element["columns"][4]["halign"] = "center";
element["columns"][4]["value"] = data["asset_permanent"].asBoolean() ? getString("asset_permanent") : LLStringUtil::null;
element["columns"][5]["column"] = "date_sort";
element["columns"][5]["type"] = "text";
element["columns"][5]["value"] = llformat("%u", (U64)date.secondsSinceEpoch());
element["columns"][6]["column"] = "asset_type";
element["columns"][6]["type"] = "integer";
element["columns"][6]["value"] = data["asset_type"].asInteger();
const S32 last_flag_value = static_cast<S32>(FSAssetBlacklist::eBlacklistFlag::LAST_FLAG);
mResultList->addElement(element, ADD_BOTTOM);
for (S32 flag_value = 1; flag_value <= last_flag_value; flag_value <<= 1)
{
if ((data.flags & flag_value) || data.flags == FSAssetBlacklist::eBlacklistFlag::NONE)
{
FSAssetBlacklist::eBlacklistFlag flag = static_cast<FSAssetBlacklist::eBlacklistFlag>(flag_value);
if (data.flags == FSAssetBlacklist::eBlacklistFlag::NONE)
flag = FSAssetBlacklist::eBlacklistFlag::NONE;
LLSD element;
element["id"] = id;
element["columns"][0]["column"] = "name";
element["columns"][0]["type"] = "text";
element["columns"][0]["value"] = !data.name.empty() ? data.name : getString("unknown_object");
element["columns"][1]["column"] = "region";
element["columns"][1]["type"] = "text";
element["columns"][1]["value"] = !data.region.empty() ? data.region : getString("unknown_region");
element["columns"][2]["column"] = "type";
element["columns"][2]["type"] = "text";
element["columns"][2]["value"] = getTypeString(data.type);
element["columns"][3]["column"] = "flags";
element["columns"][3]["type"] = "text";
element["columns"][3]["value"] = getFlagString(flag);
element["columns"][4]["column"] = "date";
element["columns"][4]["type"] = "text";
element["columns"][4]["value"] = date_str;
element["columns"][5]["column"] = "permanent";
element["columns"][5]["type"] = "text";
element["columns"][5]["halign"] = "center";
element["columns"][5]["value"] = data.permanent ? getString("asset_permanent") : LLStringUtil::null;
element["columns"][6]["column"] = "date_sort";
element["columns"][6]["type"] = "text";
element["columns"][6]["value"] = llformat("%u", (U64)data.date.secondsSinceEpoch());
element["columns"][7]["column"] = "asset_type";
element["columns"][7]["type"] = "integer";
element["columns"][7]["value"] = (S32)data.type;
LLSD value;
value["flag"] = static_cast<S32>(flag);
element["alt_value"] = value;
mResultList->addElement(element, ADD_BOTTOM);
if (data.flags == FSAssetBlacklist::eBlacklistFlag::NONE)
break;
}
}
}
void FSFloaterAssetBlacklist::removeElements()
{
uuid_vec_t items;
std::map<LLUUID, S32> flags_to_remove_by_id;
for (auto listitem : mResultList->getAllSelected())
{
items.emplace_back(listitem->getUUID());
LLUUID id = listitem->getUUID();
LLSD value = listitem->getAltValue();
if (value.has("flag"))
{
S32 flag = value["flag"].asInteger();
flags_to_remove_by_id[id] |= flag;
}
else
{
// fallback: remove full item
FSAssetBlacklist::instance().removeItemsFromBlacklist({ id });
}
}
FSAssetBlacklist::instance().removeItemsFromBlacklist(items);
for (const auto& [id, flags] : flags_to_remove_by_id)
{
FSAssetBlacklist::instance().removeFlagsFromItem(id, flags);
}
}
void FSFloaterAssetBlacklist::onBlacklistChanged(const LLSD& data, FSAssetBlacklist::eBlacklistOperation op)
void FSFloaterAssetBlacklist::onBlacklistChanged(const FSAssetBlacklist::changed_signal_data_t& data, FSAssetBlacklist::eBlacklistOperation op)
{
if (op == FSAssetBlacklist::eBlacklistOperation::BLACKLIST_ADD)
{
bool need_sort = mResultList->isSorted();
mResultList->setNeedsSort(false);
for (LLSD::map_const_iterator it = data.beginMap(); it != data.endMap(); ++it)
for (const auto& [id, data] : data)
{
LLUUID id = LLUUID(it->first);
LLSD insert_data = it->second;
addElementToList(id, insert_data);
mResultList->deleteItems(id);
if (data.has_value())
{
addElementToList(id, data.value());
}
}
mResultList->setNeedsSort(need_sort);
@ -194,9 +262,9 @@ void FSFloaterAssetBlacklist::onBlacklistChanged(const LLSD& data, FSAssetBlackl
}
else
{
for (LLSD::array_const_iterator it = data.beginArray(); it != data.endArray(); ++it)
for (const auto& [id, data] : data)
{
mResultList->deleteItems(*it);
mResultList->deleteItems(id);
}
mResultList->updateLayout();
}

View File

@ -50,7 +50,7 @@ public:
bool tick() override;
void closeFloater(bool app_quitting = false) override;
void addElementToList(const LLUUID& id, const LLSD& data);
void addElementToList(const LLUUID& id, const FSAssetBlacklistData& data);
void removeElements();
protected:
@ -60,11 +60,13 @@ protected:
void onStopBtn();
void onCloseBtn();
void onFilterEdit(const std::string& search_string);
void onBlacklistChanged(const LLSD& data, FSAssetBlacklist::eBlacklistOperation op);
void onBlacklistChanged(const FSAssetBlacklist::changed_signal_data_t& data, FSAssetBlacklist::eBlacklistOperation op);
void onSelectionChanged();
void buildBlacklist();
std::string getTypeString(S32 type);
std::string getTypeString(S32 type) const;
std::string getFlagString(FSAssetBlacklist::eBlacklistFlag source) const;
static FSAssetBlacklist::eBlacklistFlag getFlagFromLLSD(const LLSD& data);
LLUUID mAudioSourceID;

View File

@ -648,8 +648,7 @@ void FSFloaterContacts::addFriend(const LLUUID& agent_id)
{
const LLRelationship* info = at.getBuddyInfo(agent_id);
LLUUID request_id = LLUUID::generateNewID();
LLAvatarNameCache::callback_connection_t conn = LLAvatarNameCache::get(agent_id, boost::bind(&FSFloaterContacts::updateFriendItem, this, agent_id, info, request_id));
mAvatarNameCacheConnections[request_id] = conn;
mAvatarNameCacheConnections.try_emplace(request_id, LLAvatarNameCache::get(agent_id, boost::bind(&FSFloaterContacts::updateFriendItem, this, agent_id, info, request_id)));
}
LLSD element;
@ -742,8 +741,7 @@ void FSFloaterContacts::updateFriendItem(const LLUUID& agent_id, const LLRelatio
if (!LLAvatarNameCache::get(agent_id, &av_name))
{
LLUUID request_id = LLUUID::generateNewID();
LLAvatarNameCache::callback_connection_t conn = LLAvatarNameCache::get(agent_id, boost::bind(&FSFloaterContacts::updateFriendItem, this, agent_id, info, request_id));
mAvatarNameCacheConnections[request_id] = conn;
mAvatarNameCacheConnections.try_emplace(request_id, LLAvatarNameCache::get(agent_id, boost::bind(&FSFloaterContacts::updateFriendItem, this, agent_id, info, request_id)));
}
// Name of the status icon to use
@ -1250,21 +1248,19 @@ void FSFloaterContacts::onColumnDisplayModeChanged(const std::string& settings_n
void FSFloaterContacts::onDisplayNameChanged()
{
listitem_vec_t items = mFriendsList->getAllData();
for (listitem_vec_t::iterator it = items.begin(); it != items.end(); ++it)
for (auto item : mFriendsList->getAllData())
{
LLAvatarName av_name;
if (LLAvatarNameCache::get((*it)->getUUID(), &av_name))
if (LLAvatarNameCache::get(item->getUUID(), &av_name))
{
(*it)->getColumn(LIST_FRIEND_USER_NAME)->setValue(av_name.getUserNameForDisplay());
(*it)->getColumn(LIST_FRIEND_DISPLAY_NAME)->setValue(av_name.getDisplayName());
(*it)->getColumn(LIST_FRIEND_NAME)->setValue(getFullName(av_name));
item->getColumn(LIST_FRIEND_USER_NAME)->setValue(av_name.getUserNameForDisplay());
item->getColumn(LIST_FRIEND_DISPLAY_NAME)->setValue(av_name.getDisplayName());
item->getColumn(LIST_FRIEND_NAME)->setValue(getFullName(av_name));
}
else
{
LLUUID request_id = LLUUID::generateNewID();
LLAvatarNameCache::callback_connection_t conn = LLAvatarNameCache::get((*it)->getUUID(), boost::bind(&FSFloaterContacts::setDirtyNames, this, request_id));
mAvatarNameCacheConnections[request_id] = conn;
mAvatarNameCacheConnections.try_emplace(request_id, LLAvatarNameCache::get(item->getUUID(), boost::bind(&FSFloaterContacts::setDirtyNames, this, request_id)));
}
}
mFriendsList->setNeedsSort();

View File

@ -2427,7 +2427,7 @@ bool FSFloaterPoser::savePoseToBvh(LLVOAvatar* avatar, const std::string& poseFi
return false;
}
return true;
return writeSuccess;
}
bool FSFloaterPoser::writePoseAsBvh(llofstream* fileStream, LLVOAvatar* avatar)
@ -2454,7 +2454,6 @@ void FSFloaterPoser::writeBvhFragment(llofstream* fileStream, LLVOAvatar* avatar
if (!joint)
return;
auto position = mPoserAnimator.getJointPosition(avatar, *joint);
auto saveAxis = getBvhJointTranslation(joint->jointName());
switch (joint->boneType())
@ -2559,7 +2558,7 @@ void FSFloaterPoser::writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar,
switch (joint->boneType())
{
case WHOLEAVATAR:
*fileStream << vec3ToXYZString(position) + " " + rotationToString(rotation);
*fileStream << positionToString(position) + " " + rotationToString(rotation);
break;
default:
@ -2575,9 +2574,10 @@ void FSFloaterPoser::writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar,
}
}
std::string FSFloaterPoser::vec3ToXYZString(const LLVector3& val)
std::string FSFloaterPoser::positionToString(const LLVector3& val)
{
return std::to_string(val[VX]) + " " + std::to_string(val[VY]) + " " + std::to_string(val[VZ]);
const float metresToInches = 39.37008f;
return std::to_string(metresToInches * val[VY]) + " " + std::to_string(metresToInches * val[VZ]) + " " + std::to_string(metresToInches * val[VX]);
}
std::string FSFloaterPoser::rotationToString(const LLVector3& val)

View File

@ -426,7 +426,7 @@ public:
/// <summary>
/// Transforms the supplied vector into a string of three numbers, format suiting to writing into a BVH file.
/// </summary>
std::string static vec3ToXYZString(const LLVector3& val);
std::string static positionToString(const LLVector3& val);
/// <summary>
/// Performs an angle module of the supplied value to between -180 & 180 (degrees).

View File

@ -74,9 +74,14 @@ FSPrimfeedPhotoPanel::FSPrimfeedPhotoPanel() :
mDescriptionTextBox(nullptr),
mLocationCheckbox(nullptr),
mRatingComboBox(nullptr),
mStoresComboBox(nullptr),
mPostButton(nullptr),
mBtnPreview(nullptr),
mBigPreviewFloater(nullptr)
mBigPreviewFloater(nullptr),
mCancelButton(nullptr),
mCommercialCheckbox(nullptr),
mFilterComboBox(nullptr),
mPublicGalleryCheckbox(nullptr)
{
mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", [this](LLUICtrl*, const LLSD&) { onSend(); });
mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", [this](LLUICtrl*, const LLSD&) { onClickNewSnapshot(); });
@ -88,6 +93,16 @@ FSPrimfeedPhotoPanel::FSPrimfeedPhotoPanel() :
LL_DEBUGS("primfeed") << "Info button clicked, opening " << url << LL_ENDL;
LLWeb::loadURLExternal(url);
});
FSPrimfeedAuth::sPrimfeedAuthPump->listen("FSPrimfeedPhotoPanel",
[this](const LLSD& data)
{
if (data["responseType"].asString() == "primfeed_user_info")
{
this->loadPrimfeedInfo(data);
return true;
}
return false;
});
}
FSPrimfeedPhotoPanel::~FSPrimfeedPhotoPanel()
@ -97,8 +112,6 @@ FSPrimfeedPhotoPanel::~FSPrimfeedPhotoPanel()
mPreviewHandle.get()->die();
}
FSPrimfeedAuth::sPrimfeedAuthPump->stopListening("FSPrimfeedAccountPanel");
gSavedSettings.setS32("FSLastSnapshotToPrimfeedResolution", getChild<LLComboBox>("resolution_combobox")->getCurrentIndex());
gSavedSettings.setS32("FSLastSnapshotToPrimfeedWidth", getChild<LLSpinCtrl>("custom_snapshot_width")->getValue().asInteger());
gSavedSettings.setS32("FSLastSnapshotToPrimfeedHeight", getChild<LLSpinCtrl>("custom_snapshot_height")->getValue().asInteger());
@ -121,6 +134,7 @@ bool FSPrimfeedPhotoPanel::postBuild()
mCommercialCheckbox = getChild<LLUICtrl>("primfeed_commercial_content");
mPublicGalleryCheckbox = getChild<LLUICtrl>("primfeed_add_to_public_gallery");
mRatingComboBox = getChild<LLUICtrl>("rating_combobox");
mStoresComboBox = getChild<LLComboBox>("stores_combobox");
mPostButton = getChild<LLUICtrl>("post_photo_btn");
mCancelButton = getChild<LLUICtrl>("cancel_photo_btn");
mBigPreviewFloater = dynamic_cast<LLFloaterBigPreview*>(LLFloaterReg::getInstance("big_preview"));
@ -192,6 +206,8 @@ void FSPrimfeedPhotoPanel::draw()
mCancelButton->setEnabled(can_post);
mDescriptionTextBox->setEnabled(can_post);
mRatingComboBox->setEnabled(can_post);
// If the stores combo box is present, enable it only if we have stores to select from
mStoresComboBox->setEnabled(can_post && mStoresComboBox->getItemCount() > 1);
mResolutionComboBox->setEnabled(can_post);
mFilterComboBox->setEnabled(can_post);
mRefreshBtn->setEnabled(can_post);
@ -327,7 +343,7 @@ bool FSPrimfeedPhotoPanel::onPrimfeedConnectStateChange(const LLSD& /*data*/)
{
if (FSPrimfeedAuth::isAuthorized())
{
sendPhoto();
return true;
}
return false;
@ -352,10 +368,10 @@ void FSPrimfeedPhotoPanel::sendPhoto()
std::string description = mDescriptionTextBox->getValue().asString();
// Get the content rating
int content_rating = mRatingComboBox->getValue().asInteger();
bool post_to_public_gallery = mPublicGalleryCheckbox->getValue().asBoolean();
bool commercial_content = mCommercialCheckbox->getValue().asBoolean();
int content_rating = mRatingComboBox->getValue().asInteger();
bool post_to_public_gallery = mPublicGalleryCheckbox->getValue().asBoolean();
bool commercial_content = mCommercialCheckbox->getValue().asBoolean();
std::string store_id = mStoresComboBox->getValue().asString();
// Get the image
LLSnapshotLivePreview* previewp = getPreviewView();
@ -376,6 +392,11 @@ void FSPrimfeedPhotoPanel::sendPhoto()
params["location"] = slurl_string;
}
if (!store_id.empty())
{
// Add the store ID if we have one selected
params["store_id"] = store_id;
}
FSPrimfeedConnect::instance().uploadPhoto(params, previewp->getFormattedImage().get(),
[this](bool success, const std::string& url)
@ -529,6 +550,35 @@ void FSPrimfeedPhotoPanel::checkAspectRatio(S32 index)
}
}
void FSPrimfeedPhotoPanel::loadPrimfeedInfo(const LLSD& data)
{
if (!mStoresComboBox)
return;
// Clear any existing entries
mStoresComboBox->clearRows();
mStoresComboBox->add(LLTrans::getString("Personal"), LLSD(""));
// Read the saved stores array
const LLSD& stores = data["stores"];
if (!stores.isArray() || stores.size() == 0)
{
// No stores - disable the combobox
mStoresComboBox->setEnabled(false);
return;
}
mStoresComboBox->setEnabled(true);
for (S32 i = 0; i < stores.size(); ++i)
{
const LLSD& store = stores[i];
std::string id = store["id"].asString();
std::string name = store["name"].asString();
mStoresComboBox->add(name, LLSD(id));
}
mStoresComboBox->setCurrentByIndex(0);
}
LLUICtrl* FSPrimfeedPhotoPanel::getRefreshBtn()
{
return mRefreshBtn;
@ -536,13 +586,10 @@ LLUICtrl* FSPrimfeedPhotoPanel::getRefreshBtn()
void FSPrimfeedPhotoPanel::onOpen(const LLSD& key)
{
if (!FSPrimfeedAuth::isAuthorized())
{
// Reauthorise if necessary.
FSPrimfeedAuth::initiateAuthRequest();
LLSD dummy;
onPrimfeedConnectStateChange(dummy);
}
// Reauthorise if necessary.
FSPrimfeedAuth::initiateAuthRequest();
LLSD dummy;
onPrimfeedConnectStateChange(dummy);
}
void FSPrimfeedPhotoPanel::uploadCallback(bool success, const LLSD& response)
@ -639,9 +686,23 @@ FSPrimfeedAccountPanel::FSPrimfeedAccountPanel() :
FSPrimfeedAuth::sPrimfeedAuthPump->listen("FSPrimfeedAccountPanel",
[this](const LLSD& data)
{
bool success = data["success"].asBoolean();
primfeedAuthResponse(success, data);
return true;
if (data.has("responseType"))
{
auto response_type = data["responseType"].asString();
if (response_type == "primfeed_auth_response")
{
bool success = data["success"].asBoolean();
primfeedAuthResponse(success, data);
return true;
}
if (response_type == "primfeed_auth_reset")
{
bool success = data["success"].asBoolean();
primfeedAuthResponse(success, data);
return true;
}
}
return false;
});
setVisibleCallback([this](LLUICtrl*, bool visible) { onVisibilityChange(visible); });
@ -663,8 +724,8 @@ bool FSPrimfeedAccountPanel::postBuild()
void FSPrimfeedAccountPanel::draw()
{
FSPrimfeedConnect::EConnectionState connection_state = FSPrimfeedConnect::instance().getConnectionState();
static FSPrimfeedConnect::EConnectionState last_state = FSPrimfeedConnect::PRIMFEED_DISCONNECTED;
FSPrimfeedConnect::EConnectionState connection_state = FSPrimfeedConnect::instance().getConnectionState();
static FSPrimfeedConnect::EConnectionState last_state = FSPrimfeedConnect::PRIMFEED_DISCONNECTED;
// Update the connection state if it has changed
if (connection_state != last_state)
@ -772,14 +833,20 @@ void FSPrimfeedAccountPanel::onConnect()
{
FSPrimfeedAuth::initiateAuthRequest();
LLSD dummy;
onPrimfeedConnectStateChange(dummy);
onPrimfeedConnectStateChange(dummy);
}
void FSPrimfeedAccountPanel::onDisconnect()
{
FSPrimfeedAuth::resetAuthStatus();
LLSD dummy;
onPrimfeedConnectStateChange(dummy);
onPrimfeedConnectStateChange(dummy);
}
FSPrimfeedAccountPanel::~FSPrimfeedAccountPanel()
{
// Disconnect the primfeed auth pump
FSPrimfeedAuth::sPrimfeedAuthPump->stopListening("FSPrimfeedAccountPanel");
}
////////////////////////
@ -789,10 +856,10 @@ void FSPrimfeedAccountPanel::onDisconnect()
FSFloaterPrimfeed::FSFloaterPrimfeed(const LLSD& key) :
LLFloater(key),
mPrimfeedPhotoPanel(nullptr),
mPrimfeedAccountPanel(nullptr),
mStatusErrorText(nullptr),
mStatusLoadingText(nullptr),
mStatusLoadingIndicator(nullptr),
mPrimfeedAccountPanel(nullptr)
mStatusLoadingIndicator(nullptr)
{
mCommitCallbackRegistrar.add("SocialSharing.Cancel", [this](LLUICtrl*, const LLSD&) { onCancel(); });
}

View File

@ -34,6 +34,7 @@
class LLIconCtrl;
class LLCheckBoxCtrl;
class LLComboBox;
class LLSnapshotLivePreview;
class LLFloaterBigPreview;
@ -52,6 +53,7 @@ public:
bool postBuild() override;
S32 notify(const LLSD& info);
void draw() override;
void loadPrimfeedInfo(const LLSD& data);
LLSnapshotLivePreview* getPreviewView();
void onVisibilityChange(bool new_visibility);
@ -80,28 +82,30 @@ private:
LLHandle<LLView> mPreviewHandle;
LLUICtrl * mResolutionComboBox;
LLUICtrl * mFilterComboBox;
LLUICtrl * mRefreshBtn;
LLUICtrl * mWorkingLabel;
LLUICtrl * mThumbnailPlaceholder;
LLUICtrl * mDescriptionTextBox;
LLUICtrl * mLocationCheckbox;
LLUICtrl* mResolutionComboBox;
LLUICtrl* mFilterComboBox;
LLUICtrl* mRefreshBtn;
LLUICtrl* mWorkingLabel;
LLUICtrl* mThumbnailPlaceholder;
LLUICtrl* mDescriptionTextBox;
LLUICtrl* mLocationCheckbox;
LLUICtrl * mCommercialCheckbox;
LLUICtrl * mPublicGalleryCheckbox;
LLUICtrl * mRatingComboBox;
LLUICtrl * mPostButton;
LLUICtrl * mCancelButton;
LLButton * mBtnPreview;
LLUICtrl* mCommercialCheckbox;
LLUICtrl* mPublicGalleryCheckbox;
LLUICtrl* mRatingComboBox;
LLUICtrl* mPostButton;
LLUICtrl* mCancelButton;
LLButton* mBtnPreview;
LLComboBox* mStoresComboBox;
LLFloaterBigPreview * mBigPreviewFloater;
LLFloaterBigPreview* mBigPreviewFloater;
};
class FSPrimfeedAccountPanel : public LLPanel
{
public:
FSPrimfeedAccountPanel();
~FSPrimfeedAccountPanel();
bool postBuild() override;
void draw() override;

File diff suppressed because it is too large Load Diff

View File

@ -36,19 +36,19 @@
#include <boost/signals2.hpp>
extern const char* DEFAULT_LOGIN_PAGE;
//Kokua: for llviewernetwork_test
const S32 KNOWN_GRIDS_SIZE = 3;
// Kokua: for llviewernetwork_test
const S32 KNOWN_GRIDS_SIZE = 3;
const std::string GRID_VALUE = "name";
const std::string GRID_LABEL_VALUE = "gridname";
const std::string GRID_ID_VALUE = "grid_login_id";
const std::string GRID_LOGIN_URI_VALUE = "loginuri";
const std::string GRID_UPDATE_SERVICE_URL = "update_query_url_base";
const std::string GRID_HELPER_URI_VALUE = "helperuri";
const std::string GRID_LOGIN_PAGE_VALUE = "loginpage";
const std::string GRID_IS_SYSTEM_GRID_VALUE = "system_grid";
const std::string GRID_IS_FAVORITE_VALUE = "favorite";
const std::string GRID_LOGIN_IDENTIFIER_TYPES = "login_identifier_types";
const std::string GRID_VALUE = "name";
const std::string GRID_LABEL_VALUE = "gridname";
const std::string GRID_ID_VALUE = "grid_login_id";
const std::string GRID_LOGIN_URI_VALUE = "loginuri";
const std::string GRID_UPDATE_SERVICE_URL = "update_query_url_base";
const std::string GRID_HELPER_URI_VALUE = "helperuri";
const std::string GRID_LOGIN_PAGE_VALUE = "loginpage";
const std::string GRID_IS_SYSTEM_GRID_VALUE = "system_grid";
const std::string GRID_IS_FAVORITE_VALUE = "favorite";
const std::string GRID_LOGIN_IDENTIFIER_TYPES = "login_identifier_types";
const std::string GRID_NICK_VALUE = "gridnick";
const std::string GRID_REGISTER_NEW_ACCOUNT = "register";
@ -66,8 +66,8 @@ const std::string GRID_MESSAGE = "message";
// we need to continue to support existing forms, as slurls
// are shared between viewers that may not understand newer
// forms.
const std::string GRID_SLURL_BASE = "slurl_base";
const std::string GRID_APP_SLURL_BASE = "app_slurl_base";
const std::string GRID_SLURL_BASE = "slurl_base";
const std::string GRID_APP_SLURL_BASE = "app_slurl_base";
// Inworldz special
#define INWORLDZ_URI "inworldz.com:8002"
@ -76,24 +76,22 @@ class GridInfoRequestResponder;
struct GridEntry
{
LLSD grid;
LLSD grid;
LLXMLNodePtr info_root;
bool set_current;
std::string last_http_error;
bool set_current;
std::string last_http_error;
};
class LLInvalidGridName
{
public:
LLInvalidGridName(std::string grid) : mGrid(grid)
{
}
LLInvalidGridName(std::string grid) : mGrid(grid) {}
std::string name() { return mGrid; }
protected:
std::string mGrid;
};
/**
* @brief A class to manage the grids available to the viewer
* including persistance. This class also maintains the currently
@ -128,7 +126,7 @@ public:
void initCmdLineGrids();
void resetGrids();
// grid list management
bool isReadyToLogin() const {return mReadyToLogin;}
bool isReadyToLogin() const { return mReadyToLogin; }
// add a grid to the list of grids
void addGrid(const std::string& loginuri);
@ -140,8 +138,8 @@ public:
std::map<std::string, std::string> getKnownGrids();
// this was getGridInfo - renamed to avoid ambiguity with the OpenSim grid_info
void getGridData(const std::string& grid, LLSD &grid_info);
void getGridData(LLSD &grid_info) { getGridData(mGrid, grid_info); }
void getGridData(const std::string& grid, LLSD& grid_info);
void getGridData(LLSD& grid_info) { getGridData(mGrid, grid_info); }
// current grid management
@ -151,7 +149,7 @@ public:
void setGridChoice(const std::string& grid);
/// Return the name of a grid, given either its name or its id
std::string getGrid( const std::string &grid );
std::string getGrid(const std::string& grid) const;
/// Get the id (short form selector) for a given grid; example: "agni"
std::string getGridId(const std::string& grid);
@ -160,7 +158,7 @@ public:
std::string getGridId() { return getGridId(mGrid); }
/// Deprecated for compatibility with LL. Use getGridId() instead.
//std::string getGridNick() { return mGridList[mGrid][GRID_NICK_VALUE]; }
// std::string getGridNick() { return mGridList[mGrid][GRID_NICK_VALUE]; }
/// Get the user-friendly long form descriptor for a given grid; example: "Second Life"
std::string getGridLabel(const std::string& grid);
@ -201,67 +199,67 @@ public:
void setWebProfileUrl(const std::string& url) { mGridList[mGrid][GRID_WEB_PROFILE_VALUE] = url; }
bool hasGrid(const std::string& grid){ return mGridList.has(grid); }
bool isTemporary(){ return mGridList[mGrid].has("FLAG_TEMPORARY"); }
bool isTemporary(const std::string& grid){ return mGridList[grid].has("FLAG_TEMPORARY"); }
bool hasGrid(const std::string& grid) const { return mGridList.has(grid); }
bool isTemporary() const { return mGridList[mGrid].has("FLAG_TEMPORARY"); }
bool isTemporary(const std::string& grid) const { return mGridList[grid].has("FLAG_TEMPORARY"); }
// tell if we got this from a Hypergrid SLURL
bool isHyperGrid(const std::string& grid) { return mGridList[grid].has("HG"); }
// tell if we know how to acess this grid via Hypergrid
std::string getGatekeeper() { return getGatekeeper(mGrid); }
std::string getGatekeeper(const std::string& grid) { return mGridList[grid].has("gatekeeper") ? mGridList[grid]["gatekeeper"].asString() : std::string(); }
std::string getGridByLabel( const std::string &grid_label, bool case_sensitive = false);
std::string getGridByProbing( const std::string &probe_for, bool case_sensitive = false);
std::string getGridByGridNick( const std::string &grid_nick, bool case_sensitive = false);
std::string getGridByHostName( const std::string &host_name, bool case_sensitive = false);
std::string getGridByAttribute(const std::string &attribute, const std::string &attribute_value, bool case_sensitive );
bool isSystemGrid(const std::string& grid)
std::string getGatekeeper(const std::string& grid)
{
return mGridList.has(grid) &&
mGridList[grid].has(GRID_IS_SYSTEM_GRID_VALUE) &&
return mGridList[grid].has("gatekeeper") ? mGridList[grid]["gatekeeper"].asString() : std::string();
}
std::string getGridByLabel(const std::string& grid_label, bool case_sensitive = false) const;
std::string getGridByProbing(const std::string& probe_for, bool case_sensitive = false) const;
std::string getGridByGridNick(const std::string& grid_nick, bool case_sensitive = false) const;
std::string getGridByHostName(const std::string& host_name, bool case_sensitive = false) const;
std::string getGridByAttribute(const std::string& attribute, const std::string& attribute_value, bool case_sensitive) const;
bool isSystemGrid(const std::string& grid) const
{
return mGridList.has(grid) && mGridList[grid].has(GRID_IS_SYSTEM_GRID_VALUE) &&
mGridList[grid][GRID_IS_SYSTEM_GRID_VALUE].asBoolean();
}
bool isSystemGrid() { return isSystemGrid(mGrid); }
bool isSystemGrid() const { return isSystemGrid(mGrid); }
typedef boost::function<void(bool success)> grid_list_changed_callback_t;
typedef boost::function<void(bool success)> grid_list_changed_callback_t;
typedef boost::signals2::signal<void(bool success)> grid_list_changed_signal_t;
boost::signals2::connection addGridListChangedCallback(grid_list_changed_callback_t cb);
grid_list_changed_signal_t mGridListChangedSignal;
bool isInSecondLife();
bool isInSLMain();
bool isInSLBeta();
bool isInOpenSim();
bool isInAuroraSim();
void saveGridList();
void clearFavorites();
void addGrid(GridEntry* grid_info, AddState state);
bool isInSecondLife() const;
bool isInSLMain() const;
bool isInSLBeta() const;
bool isInOpenSim() const;
bool isInAuroraSim() const;
void saveGridList();
void addGrid(GridEntry* grid_info, AddState state);
void setClassifiedFee(const S32 classified_fee) { sClassifiedFee = classified_fee; }
S32 getClassifiedFee() { return sClassifiedFee; }
void setDirectoryFee(const S32 directory_fee) { sDirectoryFee = directory_fee; }
S32 getDirectoryFee() { return sDirectoryFee; }
void setClassifiedFee(const S32 classified_fee) { mClassifiedFee = classified_fee; }
S32 getClassifiedFee() const { return mClassifiedFee; }
void setDirectoryFee(const S32 directory_fee) { mDirectoryFee = directory_fee; }
S32 getDirectoryFee() const { return mDirectoryFee; }
private:
friend class GridInfoRequestResponder;
friend void gridDownloadComplete( LLSD const &aData, LLGridManager* mOwner, GridEntry* mData, LLGridManager::AddState mState );
friend void gridDownloadError( LLSD const &aData, LLGridManager* mOwner, GridEntry* mData, LLGridManager::AddState mState );
friend void gridDownloadComplete(LLSD const& aData, LLGridManager* mOwner, GridEntry* mData, LLGridManager::AddState mState);
friend void gridDownloadError(LLSD const& aData, LLGridManager* mOwner, GridEntry* mData, LLGridManager::AddState mState);
void incResponderCount(){++mResponderCount;}
void decResponderCount(){--mResponderCount;}
void incResponderCount() { ++mResponderCount; }
void decResponderCount() { --mResponderCount; }
void gridInfoResponderCB(GridEntry* grid_data);
void setGridData(const LLSD &grid_info) { mGridList[mGrid]=grid_info; }
S32 sClassifiedFee;
S32 sDirectoryFee;
void setGridData(const LLSD& grid_info) { mGridList[mGrid] = grid_info; }
S32 mClassifiedFee;
S32 mDirectoryFee;
protected:
void updateIsInProductionGrid();
// helper function for adding the predefined grids
@ -272,15 +270,14 @@ protected:
const std::string& helper,
const std::string& login_page);
std::string mGrid;
std::string mGridFile;
std::string mStartupGrid;
LLSD mGridList;
LLSD mConnectedGrid;
int mResponderCount;
bool mReadyToLogin;
bool mCommandLineDone;
LLSD mGridList;
LLSD mConnectedGrid;
int mResponderCount;
bool mReadyToLogin;
bool mCommandLineDone;
enum e_grid_platform
{

View File

@ -68,10 +68,10 @@
* @return void
*
*/
static void renderPulsingSphere(const LLVector3& joint_world_position, const LLColor4& color = LLColor4(1.f, 1.f, 1.f, 1.f))
static void renderPulsingSphere(const LLVector3& joint_world_position, const LLColor4& color = LLColor4(0.f, 0.f, 1.f, 0.3f))
{
constexpr float MAX_SPHERE_RADIUS = 0.05f; // Base radius in agent-space units.
constexpr float PULSE_AMPLITUDE = 0.01f; // Additional radius variation.
constexpr float MAX_SPHERE_RADIUS = 0.02f; // Base radius in agent-space units.
constexpr float PULSE_AMPLITUDE = 0.005f; // Additional radius variation.
constexpr float PULSE_FREQUENCY = 1.f; // Pulses per second.
constexpr float PULSE_TIME_DOMAIN = 5.f; // Keep the time input small.
@ -104,9 +104,8 @@ static void renderPulsingSphere(const LLVector3& joint_world_position, const LLC
LLGLDepthTest gls_depth(GL_FALSE);
gGL.pushMatrix();
{
LLColor4 color;
gGL.color4f(0.f, 0.f, 1.f, 0.3f);
gGL.diffuseColor4f(0.f, 0.f, 1.f, 0.3f);
gGL.color4fv(color.mV);
gGL.diffuseColor4fv(color.mV);
gGL.scalef(currentRadius, currentRadius, currentRadius);
@ -129,37 +128,82 @@ static void renderPulsingSphere(const LLVector3& joint_world_position, const LLC
}
}
static bool isMouseOverJoint(S32 mouseX, S32 mouseY, const LLVector3& jointWorldPos, F32 jointRadius, F32& outDistanceFromCamera)
static void renderStaticSphere(const LLVector3& joint_world_position, const LLColor4& color = LLColor4(1.f, 1.f, 0.f, .6f), float radius=0.01f)
{
LLViewerCamera* camera = LLViewerCamera::getInstance();
LLGLSUIDefault gls_ui;
gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
LLGLDepthTest gls_depth(GL_TRUE);
LLGLEnable gl_blend(GL_BLEND);
// Transform joint world position to screen coordinates
LLCoordGL jointScreenPos;
camera->projectPosAgentToScreen(jointWorldPos, jointScreenPos);
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.pushMatrix();
{
// Get the world view rect
LLRect world_view_rect = gViewerWindow->getWorldViewRectScaled();
F32 half_width = (F32)world_view_rect.getWidth() / 2.f;
F32 half_height = (F32)world_view_rect.getHeight() / 2.f;
// Translate to the joint's position
gGL.translatef(joint_world_position.mV[VX], joint_world_position.mV[VY], joint_world_position.mV[VZ]);
gGL.pushMatrix();
{
gDebugProgram.bind();
// Convert mouse coordinates to be relative to the center of the screen
LLVector2 mousePos((F32)mouseX - half_width, (F32)mouseY - half_height);
LLGLEnable cull_face(GL_CULL_FACE);
LLGLDepthTest gls_depth(GL_FALSE);
gGL.pushMatrix();
{
gGL.color4fv(color.mV);
gGL.diffuseColor4fv(color.mV);
// Convert joint screen position to be relative to the center of the screen
LLVector2 joint2d(jointScreenPos.mX - half_width, jointScreenPos.mY - half_height);
gGL.scalef(radius, radius, radius);
// Calculate the distance between mouse and joint in screen space
LLVector2 delta = joint2d - mousePos;
gSphere.render();
gGL.flush();
}
gGL.popMatrix();
// Calculate the distance from the camera to the joint
outDistanceFromCamera = (jointWorldPos - camera->getOrigin()).magVec();
gUIProgram.bind();
}
gGL.popMatrix();
}
gGL.popMatrix();
// Calculate the apparent radius of the joint on the screen
F32 apparentRadius = jointRadius * camera->getPixelMeterRatio() / outDistanceFromCamera;
// Check for OpenGL errors
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
{
LL_INFOS() << "OpenGL Error: " << err << LL_ENDL;
}
}
// Check if the mouse is within the joint's radius
return (delta.magVecSquared() < apparentRadius * apparentRadius);
bool FSManipRotateJoint::isMouseOverJoint(S32 mouseX, S32 mouseY, const LLVector3& jointWorldPos, F32 jointRadius, F32& outDistanceFromCamera, F32& outRayDistanceFromCenter) const
{
// LL_INFOS("FSManipRotateJoint") << "Checking mouse("<< mouseX << "," << mouseY << ") over joint at: " << jointWorldPos << LL_ENDL;
auto joint_center = gAgent.getPosGlobalFromAgent( jointWorldPos );
// centre in *agent* space
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(joint_center);
LLVector3 ray_pt, ray_dir;
LLManipRotate::mouseToRay(mouseX, mouseY, &ray_pt, &ray_dir);
// Vector from ray origin to sphere center
LLVector3 to_center = agent_space_center - ray_pt;
// Project that onto the ray direction
F32 proj_len = ray_dir * to_center;
if (proj_len > 0.f)
{
// Closest approach squared = |to_center|^2 (proj_len)^2
F32 closest_dist_sq = to_center.magVecSquared() - (proj_len * proj_len);
if (closest_dist_sq <= jointRadius * jointRadius)
{
// ray *does* hit the sphere; compute the entrance intersection distance
F32 offset = sqrtf(jointRadius*jointRadius - closest_dist_sq);
outDistanceFromCamera = proj_len - offset; // distance along the ray to the front intersection
outRayDistanceFromCenter = offset;
return true;
}
}
return (false);
}
//static
@ -281,12 +325,18 @@ FSManipRotateJoint::BoneAxes FSManipRotateJoint::computeBoneAxes() const
void FSManipRotateJoint::highlightHoverSpheres(S32 mouseX, S32 mouseY)
{
// Ensure we have an avatar to work with.
if (!mAvatar) return;
if (!mAvatar || mAvatar->isDead())
return;
mHighlightedJoint = nullptr; // reset the highlighted joint
// Iterate through the avatar's joint map.
for (const auto& entry : getSelectableJoints())
F32 nearest_hit_distance = 0.f;
F32 nearest_ray_distance = 0.f;
LLJoint * nearest_joint = nullptr;
for ( const auto& entry : getSelectableJoints())
{
LLJoint* joint = mAvatar->getJoint(std::string(entry));
if (!joint)
continue;
@ -297,18 +347,24 @@ void FSManipRotateJoint::highlightHoverSpheres(S32 mouseX, S32 mouseY)
// Retrieve the joint's world position (in agent space).
LLVector3 jointWorldPos = joint->getWorldPosition();
LLCachedControl<F32> target_radius(gSavedSettings, "FSManipRotateJointTargetSize", 0.2f);
LLCachedControl<F32> target_radius(gSavedSettings, "FSManipRotateJointTargetSize", 0.03f);
F32 distance_from_camera;
if (isMouseOverJoint(mouseX, mouseY, jointWorldPos, target_radius, distance_from_camera) == true)
F32 distance_from_joint;
if (isMouseOverJoint(mouseX, mouseY, jointWorldPos, target_radius, distance_from_camera, distance_from_joint) == true)
{
// we want to highlight the closest
if (!mHighlightedJoint || mHighlightedPartDistance > distance_from_camera)
// If there is no joint or
// this joint is a closer hit than the previous one
if (!nearest_joint || nearest_ray_distance > distance_from_camera ||
(nearest_ray_distance == distance_from_camera && nearest_hit_distance > distance_from_joint))
{
mHighlightedJoint = joint;
mHighlightedPartDistance = distance_from_camera;
nearest_joint = joint;
nearest_hit_distance = distance_from_joint;
nearest_ray_distance = distance_from_camera;
}
}
}
mHighlightedJoint = nearest_joint;
}
FSManipRotateJoint::FSManipRotateJoint(LLToolComposite* composite)
@ -375,6 +431,7 @@ bool FSManipRotateJoint::updateVisiblity()
if (!hasMouseCapture())
{
mRotationCenter = gAgent.getPosGlobalFromAgent( mJoint->getWorldPosition() );
mCamEdgeOn = false;
}
bool visible = false;
@ -413,13 +470,6 @@ bool FSManipRotateJoint::updateVisiblity()
}
}
mCamEdgeOn = false;
F32 axis_onto_cam = mManipPart >= LL_ROT_X ? llabs( getConstraintAxis() * mCenterToCamNorm ) : 0.f;
if (axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE)
{
mCamEdgeOn = true;
}
return visible;
}
@ -648,28 +698,50 @@ void FSManipRotateJoint::renderCenterSphere(const F32 radius, const LLColor4& no
void FSManipRotateJoint::render()
{
// Early-out if no joint or avatar.
if (!mJoint || !mAvatar)
// Needs more something: if they log out while dots on them, asplode
if (!mJoint || !mAvatar || mAvatar->isDead())
{
return;
}
// update visibility and rotation center.
if (!updateVisiblity())
{
return;
}
bool activeJointVisible = updateVisiblity();
// Setup GL state.
LLGLSUIDefault gls_ui;
gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
LLGLDepthTest gls_depth(GL_TRUE);
LLGLEnable gl_blend(GL_BLEND);
// Optionally, if another joint is highlighted, render a pulsing sphere.
if (mHighlightedJoint && mJoint != mHighlightedJoint)
// Iterate through the avatar's joint map.
// If a joint other than the currently selected is highlighted, render a pulsing sphere.
// otherwise a small static sphere
for (const auto& entry : getSelectableJoints())
{
mHighlightedJoint->updateWorldMatrixParent();
mHighlightedJoint->updateWorldMatrix();
renderPulsingSphere(mHighlightedJoint->getWorldPosition());
LLJoint* joint = mAvatar->getJoint(std::string(entry));
if (!joint)
continue;
// Update the joint's world matrix to ensure its position is current.
joint->updateWorldMatrixParent();
joint->updateWorldMatrix();
if( joint == mHighlightedJoint && joint != mJoint )
{
renderPulsingSphere(joint->getWorldPosition());
}
else if( joint != mJoint )
{
// Render a static sphere for the joint being manipulated.
LLCachedControl<bool> show_joint_markers(gSavedSettings, "FSManipShowJointMarkers", true);
if(show_joint_markers)
{
renderStaticSphere(joint->getWorldPosition(), LLColor4(1.f, 0.5f, 0.f, 0.5f), 0.01f);
}
}
}
if (!activeJointVisible)
{
return;
}
// Update joint world matrices.
@ -683,30 +755,21 @@ void FSManipRotateJoint::render()
LLQuaternion currentLocalRot = mJoint->getRotation();
LLQuaternion rotatedNaturalAlignment = mNaturalAlignmentQuat * currentLocalRot;
rotatedNaturalAlignment.normalize();
// Compute the final world alignment:
LLQuaternion final_world_alignment = rotatedNaturalAlignment * parentWorldRot;
final_world_alignment.normalize();
const LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
LLCachedControl<bool> use_natural_direction(gSavedSettings, "FSManipRotateJointUseNaturalDirection", true);
LLQuaternion active_rotation = use_natural_direction? final_world_alignment : joint_world_rotation;
active_rotation.normalize();
// Render the manipulator rings in a separate function.
gGL.matrixMode(LLRender::MM_MODELVIEW);
renderAxes(agent_space_center, mRadiusMeters * 1.5f, active_rotation);
renderManipulatorRings(agent_space_center, active_rotation);
// Debug: render joint's Euler angles for diagnostic purposes.
LLVector3 euler_angles;
active_rotation.getEulerAngles(&euler_angles.mV[0],
&euler_angles.mV[1],
&euler_angles.mV[2]);
euler_angles *= RAD_TO_DEG;
euler_angles.mV[0] = ll_round(fmodf(euler_angles.mV[0] + 360.f, 360.f), 0.05f);
euler_angles.mV[1] = ll_round(fmodf(euler_angles.mV[1] + 360.f, 360.f), 0.05f);
euler_angles.mV[2] = ll_round(fmodf(euler_angles.mV[2] + 360.f, 360.f), 0.05f);
renderNameXYZ(euler_angles);
renderNameXYZ(active_rotation);
}
void FSManipRotateJoint::renderAxes(const LLVector3& agent_space_center, F32 size, const LLQuaternion& rotation)
@ -804,13 +867,28 @@ std::string FSManipRotateJoint::getManipPartString(EManipPart part)
* @note This function assumes the existence of class member variables such as mLastAngle, mJoint, and mManipPart.
* It also uses global functions and objects like gViewerWindow, LLUI, and LLFontGL.
*/
void FSManipRotateJoint::renderNameXYZ(const LLVector3 &vec)
void FSManipRotateJoint::renderNameXYZ(const LLQuaternion& rot)
{
constexpr S32 PAD = 10;
S32 window_center_x = gViewerWindow->getWorldViewRectScaled().getWidth() / 2;
S32 window_center_y = gViewerWindow->getWorldViewRectScaled().getHeight() / 2;
S32 vertical_offset = window_center_y - VERTICAL_OFFSET;
LLVector3 euler_angles;
rot.getEulerAngles(&euler_angles.mV[0],
&euler_angles.mV[1],
&euler_angles.mV[2]);
euler_angles *= RAD_TO_DEG;
for (S32 i = 0; i < 3; ++i)
{
// Ensure angles are in the range [0, 360) and rounded to 0.05f
euler_angles.mV[i] = ll_round(fmodf(euler_angles.mV[i] + 360.f, 360.f), 0.05f);
F32 rawDelta = euler_angles.mV[i] - mLastEuler.mV[i];
if (rawDelta > 180.f) rawDelta -= 360.f;
else if (rawDelta < -180.f) rawDelta += 360.f;
mLastEuler[i] += rawDelta;
}
gGL.pushMatrix();
{
LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square");
@ -840,13 +918,22 @@ void FSManipRotateJoint::renderNameXYZ(const LLVector3 &vec)
};
F32 base_y = (F32)(window_center_y + vertical_offset);
renderTextWithShadow(llformat("X: %.3f", vec.mV[VX]), window_center_x - 122.f, base_y, LLColor4(1.f, 0.5f, 0.5f, 1.f));
renderTextWithShadow(llformat("Y: %.3f", vec.mV[VY]), window_center_x - 47.f, base_y, LLColor4(0.5f, 1.f, 0.5f, 1.f));
renderTextWithShadow(llformat("Z: %.3f", vec.mV[VZ]), window_center_x + 28.f, base_y, LLColor4(0.5f, 0.5f, 1.f, 1.f));
renderTextWithShadow(llformat("Δ: %.3f", mLastAngle * RAD_TO_DEG), window_center_x + 103.f, base_y, LLColor4(1.f, 0.65f, 0.f, 1.f));
renderTextWithShadow(llformat("X: %.3f", mLastEuler.mV[VX]), window_center_x - 122.f, base_y, LLColor4(1.f, 0.5f, 0.5f, 1.f));
renderTextWithShadow(llformat("Y: %.3f", mLastEuler.mV[VY]), window_center_x - 47.f, base_y, LLColor4(0.5f, 1.f, 0.5f, 1.f));
renderTextWithShadow(llformat("Z: %.3f", mLastEuler.mV[VZ]), window_center_x + 28.f, base_y, LLColor4(0.5f, 0.5f, 1.f, 1.f));
renderTextWithShadow(llformat(": %.3f", mLastAngle * RAD_TO_DEG), window_center_x + 103.f, base_y, LLColor4(1.f, 0.65f, 0.f, 1.f));
base_y += 20.f;
renderTextWithShadow(llformat("Joint: %s", mJoint->getName().c_str()), window_center_x - 130.f, base_y, LLColor4(1.f, 0.1f, 1.f, 1.f));
renderTextWithShadow(llformat("Manip: %s", getManipPartString(mManipPart).c_str()), window_center_x + 30.f, base_y, LLColor4(1.f, 1.f, .1f, 1.f));
renderTextWithShadow(llformat("Manip: %s%c", getManipPartString(mManipPart).c_str(), mCamEdgeOn?'*':' '), window_center_x + 30.f, base_y, LLColor4(1.f, 1.f, .1f, 1.f));
if (mManipPart != LL_NO_PART)
{
LL_INFOS("FSManipRotateJoint") << "Joint: " << mJoint->getName()
<< ", Manip: " << getManipPartString(mManipPart)
<< ", Quaternion: " << rot
<< ", Euler Angles: " << mLastEuler
<< ", Delta Angle: " << mLastAngle * RAD_TO_DEG
<< LL_ENDL;
}
}
gGL.popMatrix();
@ -934,7 +1021,7 @@ bool FSManipRotateJoint::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
// Determine which ring (axis) is under the mouse, also highlights selectable joints.
highlightManipulators(x, y);
// For joint manipulation, require both a valid joint and avatar.
if (!mJoint || !mAvatar || !poser)
if (!mJoint || !mAvatar || mAvatar->isDead() || !poser)
{
return false;
}
@ -960,9 +1047,11 @@ bool FSManipRotateJoint::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
{
// Constrained rotation.
LLVector3 axis = setConstraintAxis(); // set the axis based on the manipulator part
mLastEuler = LLVector3::zero;
F32 axis_onto_cam = llabs(axis * mCenterToCamNorm);
const F32 AXIS_ONTO_CAM_TOL = cos(85.f * DEG_TO_RAD);
if (axis_onto_cam < AXIS_ONTO_CAM_TOL)
if (axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE)
{
LLVector3 up_from_axis = mCenterToCamNorm % axis;
up_from_axis.normalize();
@ -979,11 +1068,13 @@ bool FSManipRotateJoint::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
}
LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, axis);
mMouseDown += mouse_depth * projected_center_to_cam;
mCamEdgeOn = true; // We are in edge mode, so we can use the mouse depth.
}
else
{
mMouseDown = findNearestPointOnRing(x, y, agent_space_center, axis) - agent_space_center;
mMouseDown.normalize();
mCamEdgeOn = false; // Not in edge mode, so we don't use the mouse depth.
}
mInitialIntersection = mMouseDown;
}
@ -1021,6 +1112,7 @@ bool FSManipRotateJoint::handleMouseUp(S32 x, S32 y, MASK mask)
setMouseCapture(false);
mManipPart = LL_NO_PART;
mLastAngle = 0.0f;
mCamEdgeOn = false;
return true;
}
else if(mHighlightedJoint)
@ -1051,7 +1143,7 @@ void FSManipRotateJoint::highlightManipulators(S32 x, S32 y)
mHighlightedPart = LL_NO_PART;
// Instead of using mObjectSelection->getFirstMoveableObject(),
// simply require that the joint (and the avatar) is valid.
if (!mJoint || !mAvatar)
if (!mJoint || !mAvatar || mAvatar->isDead())
{
highlightHoverSpheres(x, y);
gViewerWindow->setCursor(UI_CURSOR_ARROW);
@ -1280,13 +1372,43 @@ LLQuaternion FSManipRotateJoint::dragUnconstrained(S32 x, S32 y)
return sphere_rot * LLQuaternion(extra_angle, axis);
}
}
static LLQuaternion extractTwist(const LLQuaternion& rot, const LLVector3& axis)
{
// Copy and normalise the input (defensive)
LLQuaternion qnorm = rot;
qnorm.normalize();
// Extract vector part and scalar part
LLVector3 v(qnorm.mQ[VX], qnorm.mQ[VY], qnorm.mQ[VZ]);
F32 w = qnorm.mQ[VW];
// Project v onto the axis (removing any perpendicular component)
F32 dot = v * axis;
LLVector3 proj = axis * dot; // proj is now purely along 'axis'
// Build the “twist” quaternion from (proj, w), then renormalize
LLQuaternion twist(proj.mV[VX],
proj.mV[VY],
proj.mV[VZ],
w);
if (w < 0.f)
{
twist = -twist;
}
twist.normalize();
return twist;
}
LLQuaternion FSManipRotateJoint::dragConstrained(S32 x, S32 y)
{
// Get the constraint axis from our joint manipulator.
// (See the adjusted getConstraintAxis() below.)
LLVector3 constraint_axis = getConstraintAxis();
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
if (mCamEdgeOn)
{
LLQuaternion freeRot = dragUnconstrained(x, y);
return extractTwist(freeRot, constraint_axis);
}
// Project the current mouse position onto the plane defined by the constraint axis.
LLVector3 projected_mouse;
bool hit = getMousePointOnPlaneAgent(projected_mouse, x, y, agent_space_center, constraint_axis);

View File

@ -35,7 +35,7 @@ class LLJoint;
class LLVOAvatar; // or LLVOAvatarSelf, etc.
namespace {
const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 80.f * DEG_TO_RAD ); // cos() is not constexpr til c++26
const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 85.f * DEG_TO_RAD ); // cos() is not constexpr til c++26
constexpr F32 RADIUS_PIXELS = 100.f; // size in screen space
constexpr S32 CIRCLE_STEPS = 100;
constexpr F32 CIRCLE_STEP_SIZE = 2.0f * F_PI / CIRCLE_STEPS;
@ -83,7 +83,7 @@ public:
void handleSelect() override;
bool updateVisiblity();
void render() override;
void renderNameXYZ(const LLVector3 &vec);
void renderNameXYZ(const LLQuaternion& rot);
bool handleMouseDown(S32 x, S32 y, MASK mask) override;
bool handleMouseUp(S32 x, S32 y, MASK mask) override;
bool handleHover(S32 x, S32 y, MASK mask) override;
@ -94,7 +94,6 @@ public:
void highlightHoverSpheres(S32 mouseX, S32 mouseY);
protected:
// void renderNameXYZ(const std::string name, const LLVector3 &vec);
LLQuaternion dragUnconstrained( S32 x, S32 y );
LLQuaternion dragConstrained( S32 x, S32 y );
LLVector3 getConstraintAxis() const { return mConstraintAxis; };
@ -109,10 +108,12 @@ protected:
LLQuaternion mSavedJointRot;
LLJoint * mHighlightedJoint = nullptr;
F32 mHighlightedPartDistance = 0.f;
LLVector3 mLastEuler = LLVector3::zero; // last euler angles in degrees
LLVector3 mInitialIntersection; // The initial point on the manipulators sphere (in agent space)
const std::vector<std::string_view> getSelectableJoints(){ return sSelectableJoints; };
private:
bool isMouseOverJoint(S32 mouseX, S32 mouseY, const LLVector3& jointWorldPos, F32 jointRadius, F32& outDistanceFromCamera, F32& outDistanceFromCenter) const;
static const std::vector<std::string_view> sSelectableJoints;
// Structure holding parameters needed to render one manipulator ring.

View File

@ -33,6 +33,7 @@
#include "llagent.h"
#include "llagentdata.h"
#include "llavatarappearancedefines.h"
#include "llbutton.h"
#include "llcalc.h"
#include "llcheckboxctrl.h"
@ -760,7 +761,7 @@ void FSPanelFace::onMatTabChange()
// Since we allow both PBR and BP textures to be applied at the same time,
// we need to hide or show the GLTF material only locally based on the current tab.
gSavedSettings.setBOOL("FSShowSelectedInBlinnPhong", (curr_mat == MATMEDIA_MATERIAL));
if (curr_mat != MATMEDIA_PBR)
if (curr_mat == MATMEDIA_MATERIAL)
LLSelectMgr::getInstance()->hideGLTFMaterial();
else
LLSelectMgr::getInstance()->showGLTFMaterial();
@ -1154,6 +1155,16 @@ void FSPanelFace::onVisibilityChange(bool new_visibility)
gAgent.showLatestFeatureNotification("gltf");
}
LLPanel::onVisibilityChange(new_visibility);
// Since we allow both PBR and BP textures to be applied at the same time,
// we need to keep FSShowSelectedInBlinnPhong in sync in case we open or close the texture panel.
static LLCachedControl<bool> showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong");
bool should_hide_gltf = new_visibility && !showSelectedinBP && getCurrentMaterialType() == MATMEDIA_MATERIAL;
gSavedSettings.setBOOL("FSShowSelectedInBlinnPhong", should_hide_gltf);
if (should_hide_gltf)
{
LLSelectMgr::getInstance()->hideGLTFMaterial();
}
}
void FSPanelFace::draw()
@ -6004,13 +6015,9 @@ void FSPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
LLUUID get(LLViewerObject* object, S32 te_index)
{
LLTextureEntry *te = object->getTE(te_index);
if (te)
if (te && LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(te->getID()))
{
if ((te->getID() == IMG_USE_BAKED_EYES) || (te->getID() == IMG_USE_BAKED_HAIR) || (te->getID() == IMG_USE_BAKED_HEAD) || (te->getID() == IMG_USE_BAKED_LOWER) || (te->getID() == IMG_USE_BAKED_SKIRT) || (te->getID() == IMG_USE_BAKED_UPPER)
|| (te->getID() == IMG_USE_BAKED_LEFTARM) || (te->getID() == IMG_USE_BAKED_LEFTLEG) || (te->getID() == IMG_USE_BAKED_AUX1) || (te->getID() == IMG_USE_BAKED_AUX2) || (te->getID() == IMG_USE_BAKED_AUX3))
{
return te->getID();
}
return te->getID();
}
LLUUID id;

View File

@ -112,31 +112,25 @@ void FSPrimfeedAuth::initiateAuthRequest()
// It should be called when the user clicks the "Authenticate" button.
// Also triggered on opening the floater.
// The actual implementation is in the create() method.
if (!isAuthorized())
if (sPrimfeedAuth)
{
if (sPrimfeedAuth)
LLNotificationsUtil::add("PrimfeedAuthorizationAlreadyInProgress");
return;
}
// If no token stored, begin the login request; otherwise check user status.
sPrimfeedAuth = FSPrimfeedAuth::create(
[](bool success, const LLSD &response)
{
LLNotificationsUtil::add("PrimfeedAuthorizationAlreadyInProgress");
return;
LLSD event_data = response;
event_data["responseType"] = "primfeed_auth_response";
event_data["success"] = success;
sPrimfeedAuthPump->post(event_data);
// Now that auth is complete, clear the static pointer.
sPrimfeedAuth.reset();
}
// If no token stored, begin the login request; otherwise check user status.
sPrimfeedAuth = FSPrimfeedAuth::create(
[](bool success, const LLSD &response)
{
LLSD event_data = response;
event_data["success"] = success;
sPrimfeedAuthPump->post(event_data);
// Now that auth is complete, clear the static pointer.
sPrimfeedAuth.reset();
}
);
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING);
}
else
{
LLNotificationsUtil::add("PrimfeedAlreadyAuthorized");
}
);
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING);
}
void FSPrimfeedAuth::resetAuthStatus()
@ -147,7 +141,7 @@ void FSPrimfeedAuth::resetAuthStatus()
gSavedPerAccountSettings.setString("FSPrimfeedPlan", "");
gSavedPerAccountSettings.setString("FSPrimfeedUsername", "");
LLSD event_data;
event_data["status"] = "reset";
event_data["responseType"] = "primfeed_auth_reset";
event_data["success"] = "false";
sPrimfeedAuthPump->post(event_data);
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED);
@ -201,7 +195,8 @@ std::shared_ptr<FSPrimfeedAuth> FSPrimfeedAuth::create(authorized_callback_t cal
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING);
// If no token stored, begin the login request; otherwise check user status.
if (gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken").empty())
auth->mOauthToken = gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken");
if (auth->mOauthToken.empty())
{
auth->beginLoginRequest();
}
@ -225,6 +220,7 @@ void FSPrimfeedAuth::beginLoginRequest()
LLCore::HttpHeaders::ptr_t pHeader(new LLCore::HttpHeaders());
LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions());
pHeader->append(HTTP_OUT_HEADER_USER_AGENT, FS_PF_USER_AGENT);
pHeader->append("pf-viewer-api-key", viewer_api_key);
pHeader->append("pf-user-uuid", user_uuid);
@ -326,6 +322,7 @@ void FSPrimfeedAuth::validateRequest()
// Create and populate the headers.
LLCore::HttpHeaders::ptr_t pHeader(new LLCore::HttpHeaders());
pHeader->append(HTTP_OUT_HEADER_USER_AGENT, FS_PF_USER_AGENT);
pHeader->append("Authorization", "Bearer " + mOauthToken);
pHeader->append("pf-viewer-api-key", viewer_api_key);
pHeader->append("pf-viewer-request-id", mRequestId);
@ -398,6 +395,7 @@ void FSPrimfeedAuth::checkUserStatus()
// Create and populate the headers.
LLCore::HttpHeaders::ptr_t pHeader(new LLCore::HttpHeaders());
pHeader->append(HTTP_OUT_HEADER_USER_AGENT, FS_PF_USER_AGENT);
pHeader->append("Authorization", "Bearer " + mOauthToken);
pHeader->append("pf-viewer-api-key", viewer_api_key);
@ -429,22 +427,23 @@ void FSPrimfeedAuth::checkUserStatus()
}
void FSPrimfeedAuth::gotUserStatus(bool success, const LLSD &response)
void FSPrimfeedAuth::gotUserStatus(bool success, const LLSD &response) const
{
LL_INFOS("Primfeed") << "User status: " << response << "(" << success << ")" << LL_ENDL;
if (success && response.has("plan"))
if (success && response.has("plan") && response.has("username") && response.has("link"))
{
gSavedPerAccountSettings.setString("FSPrimfeedOAuthToken", mOauthToken);
gSavedPerAccountSettings.setString("FSPrimfeedPlan", response["plan"].asString());
gSavedPerAccountSettings.setString("FSPrimfeedProfileLink", response["link"].asString());
gSavedPerAccountSettings.setString("FSPrimfeedUsername", response["username"].asString());
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTED);
LLSD event_data = response;
event_data["responseType"] = "primfeed_user_info";
sPrimfeedAuthPump->post(event_data);
mCallback(true, response);
return;
}
else
{
LLNotificationsUtil::add("PrimfeedUserStatusFailed");
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED);
mCallback(false, response);
}
LLNotificationsUtil::add("PrimfeedUserStatusFailed");
FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED);
mCallback(false, response);
}

View File

@ -79,7 +79,7 @@ private:
// Callback when the validate response is received.
void gotValidateResponse(bool success, const LLSD &response);
// Callback when the user status response is received.
void gotUserStatus(bool success, const LLSD &response);
void gotUserStatus(bool success, const LLSD &response) const;
boost::signals2::connection mInstantMessageConnection;
boost::signals2::connection mChatMessageConnection;

View File

@ -89,6 +89,7 @@ void FSPrimfeedConnect::uploadPhotoCoro(const LLSD& params, LLImageFormatted* im
addPart("location", params["location"].asString());
}
LL_DEBUGS("primfeed") << "Adding image file header" << LL_ENDL;
body << dash << sep
<< "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << fmt << "\"" << sep
@ -119,14 +120,14 @@ void FSPrimfeedConnect::uploadPhotoCoro(const LLSD& params, LLImageFormatted* im
LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders);
std::string token = gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken");
std::string apiKey = gSavedSettings.getString("FSPrimfeedViewerApiKey");
headers->append(HTTP_OUT_HEADER_USER_AGENT, FS_PF_USER_AGENT);
headers->append("Authorization", "Bearer " + token);
headers->append("pf-viewer-api-key", apiKey);
headers->append("Content-Type", "multipart/form-data; boundary=" + boundary);
LL_DEBUGS("primfeed") << "Dumping HTTP headers for POST:" << LL_ENDL;
for (auto it = headers->begin(); it != headers->end(); ++it)
if (params.has("store_id") && !params["store_id"].asString().empty())
{
LL_DEBUGS("primfeed") << it->first << ": " << it->second << LL_ENDL;
headers->append("kynno-selected-store", params["store_id"].asString());
}
headers->append("Content-Type", "multipart/form-data; boundary=" + boundary);
LL_DEBUGS("primfeed") << "Headers set" << LL_ENDL;
LL_DEBUGS("primfeed") << "Starting HTTP POST" << LL_ENDL;
@ -181,9 +182,3 @@ bool FSPrimfeedConnect::isTransactionOngoing() const
mConnectionState == PRIMFEED_DISCONNECTING);
}
void FSPrimfeedConnect::loadPrimfeedInfo()
{
LL_DEBUGS("primfeed") << "loadPrimfeedInfo() called" << LL_ENDL;
// Nothing to do here for Primfeed
setConnectionState(PRIMFEED_CONNECTED);
}

View File

@ -39,7 +39,9 @@
#include <functional>
// Coro based connector designed to interface with floater designed along the same principles as LLFloaterFlickr.cpp
#ifndef FS_PF_USER_AGENT
#define FS_PF_USER_AGENT "Firestorm-PF"
#endif // FS_PF_USER_AGENT
class FSPrimfeedConnect : public LLSingleton<FSPrimfeedConnect>
{
LLSINGLETON(FSPrimfeedConnect);

View File

@ -63,7 +63,7 @@ class FSRadar
virtual ~FSRadar();
public:
typedef std::unordered_map<const LLUUID, std::shared_ptr<FSRadarEntry>, FSUUIDHash> entry_map_t;
typedef std::unordered_map<LLUUID, std::shared_ptr<FSRadarEntry>> entry_map_t;
entry_map_t getRadarList() { return mEntryList; }
void startTracking(const LLUUID& avatar_id);
@ -130,7 +130,7 @@ private:
bool lastIgnore;
};
typedef std::unordered_map<LLUUID, RadarFields, FSUUIDHash> radarfields_map_t;
typedef std::unordered_map<LLUUID, RadarFields> radarfields_map_t;
radarfields_map_t mLastRadarSweep;
entry_map_t mEntryList;

View File

@ -208,7 +208,7 @@ void LFSimFeatureHandler::setSupportedFeatures()
}
else if (LLGridManager::instance().isInSecondLife())
{
mAvatarPickerURL = gSavedSettings.getString("AvatarPickerURL");
mAvatarPickerURL = gSavedSettings.getString("AvatarWelcomePack");
}
else
{
@ -300,7 +300,7 @@ void LFSimFeatureHandler::setSupportedFeatures()
}
else if (in_sl)
{
mAvatarPickerURL = gSavedSettings.getString("AvatarPickerURL");
mAvatarPickerURL = gSavedSettings.getString("AvatarWelcomePack");
}
else
{

View File

@ -767,15 +767,23 @@ void LGGContactSets::setPseudonym(const LLUUID& friend_id, std::string_view pseu
inst->fetch(friend_id);
LLVOAvatar::invalidateNameTag(friend_id);
if (auto it = mAvatarNameCacheConnections.find(friend_id); it != mAvatarNameCacheConnections.end())
if (LLAvatarName av_name; LLAvatarNameCache::get(friend_id, &av_name))
{
if (it->second.connected())
{
it->second.disconnect();
}
mAvatarNameCacheConnections.erase(it);
mChangedSignal(UPDATED_MEMBERS);
}
else
{
if (auto it = mAvatarNameCacheConnections.find(friend_id); it != mAvatarNameCacheConnections.end())
{
if (it->second.connected())
{
it->second.disconnect();
}
mAvatarNameCacheConnections.erase(it);
}
mAvatarNameCacheConnections.try_emplace(friend_id, LLAvatarNameCache::get(friend_id, boost::bind(&LGGContactSets::onAvatarNameCache, this, _1)));
}
mAvatarNameCacheConnections[friend_id] = LLAvatarNameCache::get(friend_id, boost::bind(&LGGContactSets::onAvatarNameCache, this, _1));
saveToDisk();
}
@ -802,15 +810,24 @@ void LGGContactSets::clearPseudonym(const LLUUID& friend_id, bool save_changes /
removeNonFriendFromList(friend_id, save_changes);
}
if (auto it = mAvatarNameCacheConnections.find(friend_id); it != mAvatarNameCacheConnections.end())
if (LLAvatarName av_name; LLAvatarNameCache::get(friend_id, &av_name))
{
if (it->second.connected())
{
it->second.disconnect();
}
mAvatarNameCacheConnections.erase(it);
mChangedSignal(UPDATED_MEMBERS);
}
mAvatarNameCacheConnections[friend_id] = LLAvatarNameCache::get(friend_id, boost::bind(&LGGContactSets::onAvatarNameCache, this, _1));
else
{
if (auto it = mAvatarNameCacheConnections.find(friend_id); it != mAvatarNameCacheConnections.end())
{
if (it->second.connected())
{
it->second.disconnect();
}
mAvatarNameCacheConnections.erase(it);
}
mAvatarNameCacheConnections.try_emplace(friend_id, LLAvatarNameCache::get(friend_id, boost::bind(&LGGContactSets::onAvatarNameCache, this, _1)));
}
if (save_changes)
{
saveToDisk();

View File

@ -52,7 +52,7 @@ class LGGContactSets : public LLSingleton<LGGContactSets>
public:
typedef std::vector<std::string> string_vec_t;
typedef std::unordered_set<LLUUID, FSUUIDHash> uuid_set_t;
typedef std::unordered_set<LLUUID> uuid_set_t;
void loadFromDisk();
@ -157,7 +157,7 @@ private:
LLSD exportToLLSD();
void saveToDisk();
typedef std::unordered_map<LLUUID, std::string, FSUUIDHash> uuid_map_t;
typedef std::unordered_map<LLUUID, std::string> uuid_map_t;
typedef std::map<std::string, ContactSet*> contact_set_map_t;
contact_set_map_t mContactSets;

View File

@ -305,7 +305,10 @@ S32 LLAgentBenefits::get2KTextureUploadCost(S32 area) const
{
if (m_2k_texture_upload_cost.empty())
{
return m_texture_upload_cost;
// <FS:Ansariel> OpenSim legacy economy
//return m_texture_upload_cost;
return getTextureUploadCost();
// </FS:Ansariel>
}
return m_2k_texture_upload_cost[0];
}

View File

@ -2531,7 +2531,7 @@ void LLAvatarActions::derenderMultiple(const uuid_vec_t& agent_ids, bool permane
//static
void LLAvatarActions::onDerenderAvatarNameLookup(const LLUUID& agent_id, const LLAvatarName& av_name, bool permanent)
{
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(agent_id, av_name.getUserName(), "", LLAssetType::AT_PERSON, permanent, permanent);
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(agent_id, av_name.getUserName(), "", LLAssetType::AT_PERSON, FSAssetBlacklist::eBlacklistFlag::NONE, permanent, permanent);
LLViewerObject* av_obj = gObjectList.findObject(agent_id);
if (av_obj)

View File

@ -1,7 +1,7 @@
/**
* @file llfloateravatar.h
* @author Leyla Farazha
* @brief floater for the avatar changer
* @file llfloateravatarwelcomepack.cpp
* @author Callum Prentice (callum@lindenlab.com)
* @brief Floater container for the Avatar Welcome Pack we app
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
@ -27,7 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llfloateravatar.h"
#include "llfloateravatarwelcomepack.h"
#include "lluictrlfactory.h"
#include "llmediactrl.h"
@ -35,13 +35,13 @@
#include "llhttpconstants.h"
#include "llweb.h"
LLFloaterAvatar::LLFloaterAvatar(const LLSD& key)
LLFloaterAvatarWelcomePack::LLFloaterAvatarWelcomePack(const LLSD& key)
: LLFloater(key),
mAvatarPickerUrlChangedSignal() // <FS:Ansariel> Avatar chooser does not change between OpenSim grids
{
}
LLFloaterAvatar::~LLFloaterAvatar()
LLFloaterAvatarWelcomePack::~LLFloaterAvatarWelcomePack()
{
if (mAvatarPicker)
{
@ -58,32 +58,32 @@ LLFloaterAvatar::~LLFloaterAvatar()
// </FS:Ansariel>
}
bool LLFloaterAvatar::postBuild()
bool LLFloaterAvatarWelcomePack::postBuild()
{
mAvatarPicker = findChild<LLMediaCtrl>("avatar_picker_contents");
if (mAvatarPicker)
{
mAvatarPicker->clearCache();
}
enableResizeCtrls(true, true, false);
return true;
}
// <FS:Ansariel> Avatar chooser does not change between OpenSim grids
void LLFloaterAvatar::onOpen(const LLSD& key)
void LLFloaterAvatarWelcomePack::onOpen(const LLSD& key)
{
// Connect during onOpen instead of ctor because LLFloaterAvatar instance
// Connect during onOpen instead of ctor because LLFloaterAvatarWelcomePack instance
// gets created before we can safely create a LFSimFeatureHandler instance!
// Assuming we receive the avatar picker URL via login response and it
// is the same URL being sent by region caps so we will be good for the initial
// region the avatar logs into as well.
if (!mAvatarPickerUrlChangedSignal.connected())
{
mAvatarPickerUrlChangedSignal = LFSimFeatureHandler::instance().setAvatarPickerCallback(boost::bind(&LLFloaterAvatar::handleUrlChanged, this, _1));
mAvatarPickerUrlChangedSignal = LFSimFeatureHandler::instance().setAvatarPickerCallback(boost::bind(&LLFloaterAvatarWelcomePack::handleUrlChanged, this, _1));
}
}
void LLFloaterAvatar::handleUrlChanged(const std::string& url)
void LLFloaterAvatarWelcomePack::handleUrlChanged(const std::string& url)
{
getChild<LLMediaCtrl>("avatar_picker_contents")->navigateTo(LLWeb::expandURLSubstitutions(url, LLSD()), HTTP_CONTENT_TEXT_HTML);
}

View File

@ -1,7 +1,7 @@
/**
* @file llfloateravatar.h
* @author Leyla Farazha
* @brief floater for the avatar changer
* @file llfloateravatarwelcomepack.h
* @author Callum Prentice (callum@lindenlab.com)
* @brief Floater container for the Avatar Welcome Pack we app
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
@ -25,29 +25,28 @@
* $/LicenseInfo$
*/
#ifndef LL_FLOATER_AVATAR_H
#define LL_FLOATER_AVATAR_H
#pragma once
#include "llfloater.h"
class LLMediaCtrl;
class LLFloaterAvatar:
class LLFloaterAvatarWelcomePack:
public LLFloater
{
friend class LLFloaterReg;
private:
LLFloaterAvatar(const LLSD& key);
~LLFloaterAvatar();
bool postBuild() override;
LLMediaCtrl* mAvatarPicker;
private:
LLFloaterAvatarWelcomePack(const LLSD& key);
~LLFloaterAvatarWelcomePack();
bool postBuild() override;
LLMediaCtrl* mAvatarPicker;
// <FS:Ansariel> Avatar chooser does not change between OpenSim grids
/*virtual*/ void onOpen(const LLSD& key) override;
void onOpen(const LLSD& key) override;
void handleUrlChanged(const std::string& url);
boost::signals2::connection mAvatarPickerUrlChangedSignal;
// </FS:Ansariel>
};
#endif

View File

@ -68,6 +68,7 @@
#include "lluiconstants.h"
#include "lluictrlfactory.h"
#include "llviewertexturelist.h" // LLUIImageList
#include "llviewermenufile.h" // <FS:PP> Ban and access lists export/import
#include "llviewermessage.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
@ -2680,6 +2681,17 @@ bool LLPanelLandAccess::postBuild()
mBtnRemoveBanned = getChild<LLButton>("remove_banned");
mBtnRemoveBanned->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickRemoveBanned, this));
// <FS:PP> Ban and access lists export/import
mBtnExportAccess = getChild<LLButton>("export_allowed");
mBtnExportAccess->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickExportAccess, this));
mBtnExportBanned = getChild<LLButton>("export_banned");
mBtnExportBanned->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickExportBanned, this));
mBtnImportAccess = getChild<LLButton>("import_allowed");
mBtnImportAccess->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickImportAccess, this));
mBtnImportBanned = getChild<LLButton>("import_banned");
mBtnImportBanned->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickImportBanned, this));
// </FS:PP> Ban and access lists export/import
mListAccess = getChild<LLNameListCtrl>("AccessList");
if (mListAccess)
{
@ -2926,6 +2938,13 @@ void LLPanelLandAccess::refresh_ui()
mBtnAddBanned->setEnabled(false);
mBtnRemoveBanned->setEnabled(false);
// <FS:PP> Ban and access lists export/import
mBtnExportAccess->setEnabled(false);
mBtnExportBanned->setEnabled(false);
mBtnImportAccess->setEnabled(false);
mBtnImportBanned->setEnabled(false);
// </FS:PP> Ban and access lists export/import
LLParcel *parcel = mParcel->getParcel();
if (parcel && !gDisconnected)
{
@ -2995,6 +3014,14 @@ void LLPanelLandAccess::refresh_ui()
mBtnAddBanned->setEnabled(can_manage_banned && banned_list_count < PARCEL_MAX_ACCESS_LIST);
has_selected = (mListBanned && mListBanned->getSelectionInterface()->getFirstSelectedIndex() >= 0);
mBtnRemoveBanned->setEnabled(can_manage_banned && has_selected);
// <FS:PP> Ban and access lists export/import
mBtnExportAccess->setEnabled(can_manage_allowed && allowed_list_count > 0);
mBtnExportBanned->setEnabled(can_manage_banned && banned_list_count > 0);
mBtnImportAccess->setEnabled(can_manage_allowed && allowed_list_count < PARCEL_MAX_ACCESS_LIST);
mBtnImportBanned->setEnabled(can_manage_banned && banned_list_count < PARCEL_MAX_ACCESS_LIST);
// </FS:PP> Ban and access lists export/import
}
}
@ -3268,6 +3295,166 @@ void LLPanelLandAccess::onClickRemoveBanned()
}
}
// <FS:PP> Ban and access lists export/import
void LLPanelLandAccess::onClickExportList(LLNameListCtrl* list, const std::string& filename)
{
if (!list || list->getItemCount() == 0)
{
LLSD args;
args["MESSAGE"] = LLTrans::getString("ListEmpty");
LLNotificationsUtil::add("GenericAlert", args);
return;
}
LLFilePickerReplyThread::startPicker(boost::bind(&LLPanelLandAccess::exportListCallback, this, list, _1), LLFilePicker::FFSAVE_CSV, filename);
}
void LLPanelLandAccess::onClickExportAccess()
{
onClickExportList(mListAccess, "land_access_list.csv");
}
void LLPanelLandAccess::onClickExportBanned()
{
onClickExportList(mListBanned, "land_banned_list.csv");
}
void LLPanelLandAccess::exportListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames)
{
if (filenames.empty())
{
return;
}
std::string filename = filenames[0];
std::ofstream file(filename.c_str());
if (!file.is_open())
{
LLNotificationsUtil::add("ExportFailed");
return;
}
file << "Name,UUID\n";
std::vector<LLScrollListItem*> items = list->getAllData();
for (std::vector<LLScrollListItem*>::iterator it = items.begin(); it != items.end(); ++it)
{
LLScrollListItem* item = *it;
if (item)
{
const LLUUID& id = item->getUUID();
std::string name = item->getColumn(0)->getValue().asString();
file << name << "," << id.asString() << "\n";
}
}
file.close();
LLSD args;
args["FILENAME"] = filename;
LLNotificationsUtil::add("ExportFinished", args);
}
void LLPanelLandAccess::onClickImportList(LLNameListCtrl* list)
{
if (!list)
{
LLSD args;
args["MESSAGE"] = LLTrans::getString("ListEmpty");
LLNotificationsUtil::add("GenericAlert", args);
return;
}
LLFilePickerReplyThread::startPicker(boost::bind(&LLPanelLandAccess::importListCallback, this, list, _1), LLFilePicker::FFLOAD_ALL, false);
}
void LLPanelLandAccess::onClickImportAccess()
{
onClickImportList(mListAccess);
}
void LLPanelLandAccess::onClickImportBanned()
{
onClickImportList(mListBanned);
}
void LLPanelLandAccess::importListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames)
{
if (filenames.empty())
{
return;
}
std::string filename = filenames[0];
std::ifstream file(filename.c_str());
if (!file.is_open())
{
return;
}
LLParcel* parcel = mParcel->getParcel();
if (!parcel)
{
return;
}
uuid_vec_t uuids;
LLSD csvData = ll_sd_from_csv(file);
file.close();
for (const auto& entry : llsd::inArray(csvData))
{
if (entry.has("UUID"))
{
LLUUID id{ entry["UUID"].asUUID() };
if (id.notNull())
uuids.push_back(std::move(id));
}
}
if (uuids.empty())
{
LLSD args;
args["MESSAGE"] = LLTrans::getString("NoValidUUIDs");
LLNotificationsUtil::add("GenericAlert", args);
return;
}
std::string listname = list->getName();
S32 max_entries = PARCEL_MAX_ACCESS_LIST;
S32 current_count = list->getItemCount();
S32 available_slots = max_entries - current_count;
if (uuids.size() > available_slots)
{
LLSD args;
args["MAX"] = llformat("%d", available_slots);
args["COUNT"] = llformat("%d", uuids.size());
args["MESSAGE"] = LLTrans::getString("ImportListTooLarge", args).c_str();
LLNotificationsUtil::add("GenericAlert", args);
return;
}
for (const LLUUID& uuid : uuids)
{
if (listname == "BannedList")
{
parcel->addToBanList(uuid, 0);
}
else
{
parcel->addToAccessList(uuid, 0);
}
}
U32 flags = (listname == "BannedList") ? AL_BAN : AL_ACCESS;
LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(flags);
refresh();
LLSD args;
args["COUNT"] = llformat("%d", uuids.size());
args["MESSAGE"] = LLTrans::getString("ImportSuccessful", args).c_str();
LLNotificationsUtil::add("GenericAlert", args);
}
// </FS:PP> Ban and access lists export/import
//---------------------------------------------------------------------------
// LLPanelLandCovenant
//---------------------------------------------------------------------------

View File

@ -405,6 +405,17 @@ public:
void callbackAvatarCBBanned2(const uuid_vec_t& ids, S32 duration);
void callbackAvatarCBAccess(const uuid_vec_t& ids);
// <FS:PP> Ban and access lists export/import
void onClickExportAccess();
void onClickExportBanned();
void onClickExportList(LLNameListCtrl* list, const std::string& filename);
void exportListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames);
void onClickImportAccess();
void onClickImportBanned();
void onClickImportList(LLNameListCtrl* list);
void importListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames);
// </FS:PP> Ban and access lists export/import
protected:
LLNameListCtrl* mListAccess;
LLNameListCtrl* mListBanned;
@ -423,6 +434,13 @@ protected:
LLButton* mBtnAddBanned = nullptr;
LLButton* mBtnRemoveBanned = nullptr;
// <FS:PP> Ban and access lists export/import
LLButton* mBtnExportAccess = nullptr;
LLButton* mBtnExportBanned = nullptr;
LLButton* mBtnImportAccess = nullptr;
LLButton* mBtnImportBanned = nullptr;
// </FS:PP> Ban and access lists export/import
LLSafeHandle<LLParcelSelection>& mParcel;
};

View File

@ -3509,6 +3509,10 @@ bool LLPanelEstateAccess::postBuild()
childSetAction("add_allowed_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickAddAllowedAgent, this));
childSetAction("remove_allowed_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveAllowedAgent, this));
childSetAction("copy_allowed_list_btn", boost::bind(&LLPanelEstateAccess::onClickCopyAllowedList, this));
// <FS:PP> Ban and access lists export/import
childSetAction("export_allowed_list_btn", boost::bind(&LLPanelEstateAccess::onClickExportAllowedList, this));
childSetAction("import_allowed_list_btn", boost::bind(&LLPanelEstateAccess::onClickImportAllowedList, this));
// </FS:PP> Ban and access lists export/import
getChild<LLUICtrl>("allowed_group_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
LLNameListCtrl* group_name_list = getChild<LLNameListCtrl>("allowed_group_name_list");
@ -3522,6 +3526,10 @@ bool LLPanelEstateAccess::postBuild()
getChild<LLUICtrl>("add_allowed_group_btn")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onClickAddAllowedGroup, this));
childSetAction("remove_allowed_group_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveAllowedGroup, this));
childSetAction("copy_allowed_group_list_btn", boost::bind(&LLPanelEstateAccess::onClickCopyAllowedGroupList, this));
// <FS:PP> Ban and access lists export/import
childSetAction("export_allowed_group_btn", boost::bind(&LLPanelEstateAccess::onClickExportAllowedGroupList, this));
childSetAction("import_allowed_group_btn", boost::bind(&LLPanelEstateAccess::onClickImportAllowedGroupList, this));
// </FS:PP> Ban and access lists export/import
getChild<LLUICtrl>("banned_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
LLNameListCtrl* banned_name_list = getChild<LLNameListCtrl>("banned_avatar_name_list");
@ -3535,6 +3543,10 @@ bool LLPanelEstateAccess::postBuild()
childSetAction("add_banned_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickAddBannedAgent, this));
childSetAction("remove_banned_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveBannedAgent, this));
childSetAction("copy_banned_list_btn", boost::bind(&LLPanelEstateAccess::onClickCopyBannedList, this));
// <FS:PP> Ban and access lists export/import
childSetAction("export_banned_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickExportBannedList, this));
childSetAction("import_banned_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickImportBannedList, this));
// </FS:PP> Ban and access lists export/import
getChild<LLUICtrl>("estate_manager_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1));
LLNameListCtrl* manager_name_list = getChild<LLNameListCtrl>("estate_manager_name_list");
@ -3546,6 +3558,10 @@ bool LLPanelEstateAccess::postBuild()
childSetAction("add_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickAddEstateManager, this));
childSetAction("remove_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveEstateManager, this));
// <FS:PP> Ban and access lists export/import
childSetAction("export_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickExportEstateManagerList, this));
childSetAction("import_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickImportEstateManagerList, this));
// </FS:PP> Ban and access lists export/import
return true;
}
@ -3590,6 +3606,17 @@ void LLPanelEstateAccess::updateControls(LLViewerRegion* region)
getChildView("remove_estate_manager_btn")->setEnabled(has_estate_manager && (god || owner));
estateManagers->setEnabled(god || owner);
// <FS:PP> Ban and access lists export/import
getChildView("export_estate_manager_btn")->setEnabled(god || owner);
getChildView("export_allowed_list_btn")->setEnabled(enable_cotrols);
getChildView("export_allowed_group_btn")->setEnabled(enable_cotrols);
getChildView("export_banned_avatar_btn")->setEnabled(enable_cotrols);
getChildView("import_estate_manager_btn")->setEnabled(god || owner);
getChildView("import_allowed_list_btn")->setEnabled(enable_cotrols);
getChildView("import_allowed_group_btn")->setEnabled(enable_cotrols);
getChildView("import_banned_avatar_btn")->setEnabled(enable_cotrols);
// </FS:PP> Ban and access lists export/import
if (enable_cotrols != mCtrlsEnabled)
{
mCtrlsEnabled = enable_cotrols;
@ -4609,3 +4636,203 @@ void LLPanelRegionEnvironment::onChkAllowOverride(bool value)
}
}
// <FS:PP> Ban and access lists export/import
void LLPanelEstateAccess::onClickExportList(LLNameListCtrl* list, const std::string& filename)
{
if (!list || list->getItemCount() == 0)
{
LLSD args;
args["MESSAGE"] = LLTrans::getString("ListEmpty");
LLNotificationsUtil::add("GenericAlert", args);
return;
}
LLFilePickerReplyThread::startPicker(boost::bind(&LLPanelEstateAccess::exportListCallback, this, list, _1), LLFilePicker::FFSAVE_CSV, filename);
}
void LLPanelEstateAccess::onClickExportEstateManagerList()
{
onClickExportList(getChild<LLNameListCtrl>("estate_manager_name_list"), "estate_manager_list.csv");
}
void LLPanelEstateAccess::onClickExportAllowedList()
{
onClickExportList(getChild<LLNameListCtrl>("allowed_avatar_name_list"), "estate_allowed_residents.csv");
}
void LLPanelEstateAccess::onClickExportAllowedGroupList()
{
onClickExportList(getChild<LLNameListCtrl>("allowed_group_name_list"), "estate_allowed_groups.csv");
}
void LLPanelEstateAccess::onClickExportBannedList()
{
onClickExportList(getChild<LLNameListCtrl>("banned_avatar_name_list"), "estate_banned_residents.csv");
}
void LLPanelEstateAccess::exportListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames)
{
if (filenames.empty())
{
return;
}
std::string filename = filenames[0];
std::ofstream file(filename.c_str());
if (!file.is_open())
{
LLNotificationsUtil::add("ExportFailed");
return;
}
std::string listname = list->getName();
file << "Name,UUID";
if (listname == "banned_avatar_name_list")
{
file << ",Last Login,Ban Date,Banned By";
}
file << "\n";
std::vector<LLScrollListItem*> items = list->getAllData();
for (std::vector<LLScrollListItem*>::iterator it = items.begin(); it != items.end(); ++it)
{
LLScrollListItem* item = *it;
if (item)
{
const LLUUID& id = item->getUUID();
std::string name = item->getColumn(0)->getValue().asString();
file << name << "," << id.asString();
if (listname == "banned_avatar_name_list")
{
std::string last_login = item->getColumn(1)->getValue().asString();
std::string ban_date = item->getColumn(2)->getValue().asString();
std::string banned_by = item->getColumn(3)->getValue().asString();
file << "," << last_login << "," << ban_date << "," << banned_by;
}
file << "\n";
}
}
file.close();
LLSD args;
args["FILENAME"] = filename;
LLNotificationsUtil::add("ExportFinished", args);
}
void LLPanelEstateAccess::onClickImportList(LLNameListCtrl* list)
{
if (!list)
{
LLSD args;
args["MESSAGE"] = LLTrans::getString("ListEmpty");
LLNotificationsUtil::add("GenericAlert", args);
return;
}
LLFilePickerReplyThread::startPicker(boost::bind(&LLPanelEstateAccess::importListCallback, this, list, _1), LLFilePicker::FFLOAD_ALL, false);
}
void LLPanelEstateAccess::onClickImportEstateManagerList()
{
onClickImportList(getChild<LLNameListCtrl>("estate_manager_name_list"));
}
void LLPanelEstateAccess::onClickImportAllowedList()
{
onClickImportList(getChild<LLNameListCtrl>("allowed_avatar_name_list"));
}
void LLPanelEstateAccess::onClickImportAllowedGroupList()
{
onClickImportList(getChild<LLNameListCtrl>("allowed_group_name_list"));
}
void LLPanelEstateAccess::onClickImportBannedList()
{
onClickImportList(getChild<LLNameListCtrl>("banned_avatar_name_list"));
}
void LLPanelEstateAccess::importListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames)
{
if (filenames.empty())
{
return;
}
std::string filename = filenames[0];
std::ifstream file(filename.c_str());
if (!file.is_open())
{
return;
}
uuid_vec_t uuids;
LLSD csvData = ll_sd_from_csv(file);
file.close();
for (const auto& entry : llsd::inArray(csvData))
{
if (entry.has("UUID"))
{
LLUUID id{ entry["UUID"].asUUID() };
if (id.notNull())
uuids.push_back(std::move(id));
}
}
if (uuids.empty())
{
LLSD args;
args["MESSAGE"] = LLTrans::getString("NoValidUUIDs");
LLNotificationsUtil::add("GenericAlert", args);
return;
}
std::string listname = list->getName();
S32 max_entries = list->getMaxItemCount();
S32 current_count = list->getItemCount();
S32 available_slots = max_entries - current_count;
if (uuids.size() > available_slots)
{
LLSD args;
args["MAX"] = llformat("%d", available_slots);
args["COUNT"] = llformat("%d", uuids.size());
args["MESSAGE"] = LLTrans::getString("ImportListTooLarge", args).c_str();
LLNotificationsUtil::add("GenericAlert", args);
return;
}
for (const LLUUID& uuid : uuids)
{
if (listname == "banned_avatar_name_list")
{
sendEstateAccessDelta(ESTATE_ACCESS_BANNED_AGENT_ADD, uuid);
}
else if (listname == "estate_manager_name_list")
{
sendEstateAccessDelta(ESTATE_ACCESS_MANAGER_ADD, uuid);
}
else if (listname == "allowed_avatar_name_list")
{
sendEstateAccessDelta(ESTATE_ACCESS_ALLOWED_AGENT_ADD, uuid);
}
else if (listname == "allowed_group_name_list")
{
sendEstateAccessDelta(ESTATE_ACCESS_ALLOWED_GROUP_ADD, uuid);
}
}
LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess();
if (panel)
{
panel->setPendingUpdate(true);
}
LLSD args;
args["COUNT"] = llformat("%d", uuids.size());
args["MESSAGE"] = LLTrans::getString("ImportSuccessful", args).c_str();
LLNotificationsUtil::add("GenericAlert", args);
}
// </FS:PP> Ban and access lists export/import

View File

@ -508,6 +508,21 @@ public:
// <FS:Ansariel> Moved to public
static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id);
// <FS:PP> Ban and access lists export/import
void onClickExportEstateManagerList();
void onClickExportAllowedList();
void onClickExportAllowedGroupList();
void onClickExportBannedList();
void onClickExportList(LLNameListCtrl* list, const std::string& filename);
void exportListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames);
void onClickImportEstateManagerList();
void onClickImportAllowedList();
void onClickImportAllowedGroupList();
void onClickImportBannedList();
void onClickImportList(LLNameListCtrl* list);
void importListCallback(LLNameListCtrl* list, const std::vector<std::string>& filenames);
// </FS:PP> Ban and access lists export/import
private:
void onClickAddAllowedAgent();
void onClickRemoveAllowedAgent();

View File

@ -60,7 +60,7 @@ static void touch_default_probe(LLReflectionMap* probe)
}
}
LLHeroProbeManager::LLHeroProbeManager():mMirrorNormal(0,0,1) // <FS:Beq/> [FIRE-35007][#3331] mirrors not working after relog. make sure the mirror normal is not zero length
LLHeroProbeManager::LLHeroProbeManager()
{
}
@ -540,10 +540,22 @@ void LLHeroProbeManager::updateUniforms()
void LLHeroProbeManager::renderDebug()
{
gDebugProgram.bind();
// <FS:Beq> Add a bit more metadata to the probe debug view
std::map<LLSpatialGroup*, int> groupCount;
std::map<LLViewerObject*, int> objCount;
std::map<F32*, int> locCount;
for (LLReflectionMap* probe : mProbes)
{
if (!probe->isRelevant()) continue;
groupCount[ probe->mGroup ]++;
objCount[ probe->mViewerObject ]++;
locCount[ probe->mOrigin.getF32ptr() ]++;
}
// </FS:Beq>
for (auto& probe : mProbes)
{
renderReflectionProbe(probe);
renderReflectionProbe(probe, groupCount, objCount, locCount); // <FS:Beq/> Add a bit more metadata to the probe debug view
}
gDebugProgram.unbind();
@ -658,7 +670,7 @@ bool LLHeroProbeManager::registerViewerObject(LLVOVolume* drawablep)
// Probe isn't in our list for consideration. Add it.
mHeroVOList.push_back(drawablep);
return true;
}
}
return false;
}
@ -680,6 +692,6 @@ void LLHeroProbeManager::unregisterViewerObject(LLVOVolume* drawablep)
mDefaultProbe->mViewerObject = nullptr;
}
}
// </FS:Beq>
// </FS:Beq>
}

View File

@ -254,6 +254,16 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
}
std::string mfa_hash = gSavedSettings.getString("MFAHash"); //non-persistent to enable testing
// <FS:Beq> add some debug output for mfa_hash
if (mfa_hash.empty())
{
LL_DEBUGS("MFA") << "MFA hash from settings is empty (expected)" << LL_ENDL;
}
else
{
LL_DEBUGS("MFA") << "MFA hash from settings is set to: " << mfa_hash << LL_ENDL;
}
// </FS:Beq>
std::string grid(LLGridManager::getInstance()->getGridId());
std::string user_id = user_credential->userID();
if (gSecAPIHandler)
@ -266,9 +276,20 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
{
mfa_hash = data_map[user_id].asString();
}
// <FS:Beq> add some debug output for mfa_hash
if (mfa_hash.empty())
{
LL_DEBUGS("MFA") << "MFA hash from secuire store is empty" << LL_ENDL;
}
else
{
LL_DEBUGS("MFA") << "MFA hash is from secure store set to: " << mfa_hash << LL_ENDL;
}
// </FS:Beq>
}
else
{
LL_DEBUGS("MFA") << "MFA hash written to protected map" << LL_ENDL; // <FS:Beq/> add some debug output for mfa_hash
// SL-16888 the mfa_hash is being overridden for testing so save it for consistency for future login requests
gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, mfa_hash);
}
@ -277,8 +298,8 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
{
LL_WARNS() << "unable to access protected store for mfa_hash" << LL_ENDL;
}
request_params["mfa_hash"] = mfa_hash;
LL_DEBUGS("MFA") << "mfa_hash in request params is set to: " << request_params["mfa_hash"] << LL_ENDL; // <FS:Beq/> add some debug output for mfa_hash
// Specify desired timeout/retry options
LLSD http_params;
@ -622,17 +643,47 @@ void LLLoginInstance::saveMFAHash(LLSD const& response)
{
std::string grid(LLGridManager::getInstance()->getGridId());
std::string user_id(LLStartUp::getUserId());
// Only save mfa_hash for future logins if the user wants their info remembered.
// <FS:Beq> add some debug output for mfa_hash
LL_DEBUGS("MFA") << "In saveMFAHagsh, grid: " << grid
<< ", user_id: " << user_id
<< ", remember user: " << (gSavedSettings.getBOOL("RememberUser")? "true" : "false")
<< ", saveMFA: " << (LLLoginInstance::getInstance()->saveMFA()? "true" : "false")
<< LL_ENDL;
if (response.has("mfa_hash"))
{
LL_DEBUGS("MFA") << "In saveMFAHash, mfa_hash: " << response["mfa_hash"].asString()
<< LL_ENDL;
}
else
{
LL_DEBUGS("MFA") << "In saveMFAHash, no mfa_hash in response"
<< LL_ENDL;
}
// </FS:Beq>
if (response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && LLLoginInstance::getInstance()->saveMFA())
{
// <FS:Beq> add some debug output for mfa_hash
LL_DEBUGS("MFA") << "In saveMFAHash, mfa_hash: " << response["mfa_hash"].asString()
<< LL_ENDL;
// </FS:Beq>
gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]);
}
else if (!LLLoginInstance::getInstance()->saveMFA())
{
// <FS:Beq> add some debug output for mfa_hash
LL_DEBUGS("MFA") << "In saveMFAHash, removing mfa_hash from protected map"
<< LL_ENDL;
// User does not want to save mfa_hash, remove it from the protected map
gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id);
}
// TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically
// <FS:Beq> add some debug output for mfa_hash
LL_DEBUGS("MFA") << "In saveMFAHash, syncing protected map"
<< LL_ENDL;
gSecAPIHandler->syncProtectedMap();
}

View File

@ -546,6 +546,13 @@ bool LLMaterialEditor::postBuild()
getChild<LLUICtrl>("total_upload_fee")->setTextArg("[FEE]", llformat("%d", 0));
}
// <FS:TJ> [FIRE-35544] For disabling texture previews for no-mod materials
mBaseColorTextureCtrl->setIsPreviewDisabled(true);
mMetallicTextureCtrl->setIsPreviewDisabled(true);
mEmissiveTextureCtrl->setIsPreviewDisabled(true);
mNormalTextureCtrl->setIsPreviewDisabled(true);
// </FS:TJ>
// Todo:
// Disable/enable setCanApplyImmediately() based on
// working from inventory, upload or editing inworld

View File

@ -1761,7 +1761,8 @@ bool LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
LLMenuItemCallGL::Params p;
p.name = llformat("Profile Item %d", itAgent - mClosestAgentsToCursor.begin());
LLAvatarName avName; const LLUUID& idAgent = *itAgent;
LLAvatarName avName;
const LLUUID& idAgent = *itAgent;
if (LLAvatarNameCache::get(idAgent, &avName))
{
p.label = avName.getCompleteName();
@ -1778,7 +1779,7 @@ bool LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
}
mAvatarNameCacheConnections.erase(it);
}
mAvatarNameCacheConnections[idAgent] = LLAvatarNameCache::get(idAgent, boost::bind(&LLNetMap::setAvatarProfileLabel, this, _1, _2, p.name.getValue()));
mAvatarNameCacheConnections.try_emplace(idAgent, LLAvatarNameCache::get(idAgent, boost::bind(&LLNetMap::setAvatarProfileLabel, this, _1, _2, p.name.getValue())));
}
p.on_click.function = boost::bind(&LLAvatarActions::showProfile, _2);
p.on_click.parameter = idAgent;

View File

@ -63,7 +63,7 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
mTooManySelected(),
mCloseCallback(NULL),
mCloseCallbackUserData(NULL),
mAvatarNameCacheConnection(),
//mAvatarNameCacheConnection(), // <FS:Ansariel> Fix avatar name loading
mRoleNames(NULL),
mOwnerWarning(),
mAlreadyInGroup(),
@ -74,10 +74,19 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
{
if (mAvatarNameCacheConnection.connected())
// <FS:Ansariel> Fix avatar name loading
//if (mAvatarNameCacheConnection.connected())
//{
// mAvatarNameCacheConnection.disconnect();
//}
for (auto& [id, connection] : mAvatarNameCacheConnections)
{
mAvatarNameCacheConnection.disconnect();
if (connection.connected())
connection.disconnect();
}
mAvatarNameCacheConnections.clear();
// </FS:Ansariel>
}
void LLPanelGroupBulkImpl::callbackClickAdd(LLPanelGroupBulk* panelp)
@ -134,26 +143,51 @@ void LLPanelGroupBulkImpl::addUsers(const uuid_vec_t& agent_ids)
}
else
{
if (mAvatarNameCacheConnection.connected())
// <FS:Ansariel> Fix avatar name loading
//if (mAvatarNameCacheConnection.connected())
//{
// mAvatarNameCacheConnection.disconnect();
//}
//// *TODO : Add a callback per avatar name being fetched.
//mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id,
// [&](const LLUUID& agent_id, const LLAvatarName& av_name)
// {
// onAvatarNameCache(agent_id, av_name);
// });
if (auto found = mAvatarNameCacheConnections.find(agent_id); found != mAvatarNameCacheConnections.end())
{
mAvatarNameCacheConnection.disconnect();
if (found->second.connected())
found->second.disconnect();
mAvatarNameCacheConnections.erase(found);
}
// *TODO : Add a callback per avatar name being fetched.
mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_id,
mAvatarNameCacheConnections.try_emplace(agent_id, LLAvatarNameCache::get(agent_id,
[&](const LLUUID& agent_id, const LLAvatarName& av_name)
{
onAvatarNameCache(agent_id, av_name);
});
}));
// </FS:Ansariel>
}
}
}
void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
{
if (mAvatarNameCacheConnection.connected())
// <FS:Ansariel> Fix avatar name loading
//if (mAvatarNameCacheConnection.connected())
//{
// mAvatarNameCacheConnection.disconnect();
//}
if (auto found = mAvatarNameCacheConnections.find(agent_id); found != mAvatarNameCacheConnections.end())
{
mAvatarNameCacheConnection.disconnect();
if (found->second.connected())
found->second.disconnect();
mAvatarNameCacheConnections.erase(found);
}
// </FS:Ansariel>
std::vector<std::string> names;
uuid_vec_t agent_ids;

View File

@ -84,7 +84,9 @@ public:
void (*mCloseCallback)(void* data);
void* mCloseCallbackUserData;
boost::signals2::connection mAvatarNameCacheConnection;
// <FS:Ansariel> Fix avatar name loading
//boost::signals2::connection mAvatarNameCacheConnection;
std::map<LLUUID, boost::signals2::connection> mAvatarNameCacheConnections;
// The following are for the LLPanelGroupInvite subclass only.
// These aren't needed for LLPanelGroupBulkBan, but if we have to add another

View File

@ -127,7 +127,7 @@ private:
S32 sortMembersList(S32,const LLScrollListItem*,const LLScrollListItem*);
LLGroupMgrGroupData::member_list_t::iterator mMemberProgress;
typedef std::unordered_map<LLUUID, boost::signals2::connection, FSUUIDHash> avatar_name_cache_connection_map_t;
typedef std::unordered_map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
bool mPendingMemberUpdate;

View File

@ -245,7 +245,7 @@ namespace LLPerfStats
static void updateMeanFrameTime(U64 tot_frame_time_raw);
// StatsArray is a uint64_t for each possible statistic type.
using StatsArray = std::array<uint64_t, static_cast<size_t>(LLPerfStats::StatType_t::STATS_COUNT)>;
using StatsMap = std::unordered_map<LLUUID, StatsArray, FSUUIDHash>; // <FS:Beq/>
using StatsMap = std::unordered_map<LLUUID, StatsArray>; // <FS:Beq/>
using StatsTypeMatrix = std::array<StatsMap, static_cast<size_t>(LLPerfStats::ObjType_t::OT_COUNT)>;
using StatsSummaryArray = std::array<StatsArray, static_cast<size_t>(LLPerfStats::ObjType_t::OT_COUNT)>;

View File

@ -291,25 +291,54 @@ bool LLReflectionMap::isActive() const
bool LLReflectionMap::isRelevant() const
{
static LLCachedControl<S32> RenderReflectionProbeLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
static LLCachedControl<S32> sRenderReflectionProbeLevel(gSavedSettings, "RenderReflectionProbeLevel", (S32)ProbeLevel::FULL_SCENE_WITH_AUTO);
// <FS:Beq> [FIRE-35070] Correct isRelevant() logic for coverage == None and refactor to make it less fragile
// if (mViewerObject && RenderReflectionProbeLevel > 0)
// { // not an automatic probe
// return true;
// }
if (mViewerObject && RenderReflectionProbeLevel > 0)
{ // not an automatic probe
// if (RenderReflectionProbeLevel == 3)
// { // all automatics are relevant
// return true;
// }
// if (RenderReflectionProbeLevel == 2)
// { // terrain and water only, ignore probes that have a group
// return !mGroup;
// }
// // no automatic probes, yes manual probes
// return mViewerObject != nullptr;
// Implied logic: a probe has a group if it is either a manual or automatic, it has an object if it is manual
// hasGroup hasObject (in parenthesis means condition not checked)
// Manual true true
// Terrain/Water false (false)
// Automatic true false
const bool is_manual = mViewerObject != nullptr ;
const bool is_automatic = mGroup != nullptr && !is_manual;
const bool is_terrain = mGroup == nullptr;
switch (sRenderReflectionProbeLevel)
{
case (S32)ProbeLevel::NONE:
// no probes are relevant
return false;
case (S32)ProbeLevel::MANUAL_ONLY:
// only manual probes are relevant
return is_manual;
case (S32)ProbeLevel::MANUAL_AND_TERRAIN:
// manual probes and terrain/water probes are relevant
return !is_automatic;
case (S32)ProbeLevel::FULL_SCENE_WITH_AUTO:
// all probes are relevant
return true;
default:
LL_WARNS() << "Unknown RenderReflectionProbeLevel: " << (S32)sRenderReflectionProbeLevel()
<< " - returning false" << LL_ENDL;
return false;
}
if (RenderReflectionProbeLevel == 3)
{ // all automatics are relevant
return true;
}
if (RenderReflectionProbeLevel == 2)
{ // terrain and water only, ignore probes that have a group
return !mGroup;
}
// no automatic probes, yes manual probes
return mViewerObject != nullptr;
// </FS:Beq>
}

View File

@ -44,6 +44,13 @@ public:
IRRADIANCE,
REFLECTION
};
enum class ProbeLevel
{
NONE = 0,
MANUAL_ONLY,
MANUAL_AND_TERRAIN,
FULL_SCENE_WITH_AUTO
};
// allocate an environment map of the given resolution
LLReflectionMap();

View File

@ -223,7 +223,7 @@ void LLReflectionMapManager::update()
}
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
// static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3); // <FS:Beq/> No longer required use the pipeline cached version instead
static LLCachedControl<U32> sReflectionProbeCount(gSavedSettings, "RenderReflectionProbeCount", 256U);
static LLCachedControl<S32> sProbeDynamicAllocation(gSavedSettings, "RenderReflectionProbeDynamicAllocation", -1);
mResetFade = llmin((F32)(mResetFade + gFrameIntervalSeconds * 2.f), 1.f);
@ -232,15 +232,15 @@ void LLReflectionMapManager::update()
U32 probe_count_temp = mDynamicProbeCount;
if (sProbeDynamicAllocation > -1)
{
if (sLevel == 0)
if (LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::NONE)// <FS:Beq/> No longer required use the pipeline cached version instead
{
mDynamicProbeCount = 1;
}
else if (sLevel == 1)
else if (LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::MANUAL_ONLY)// <FS:Beq/> No longer required use the pipeline cached version instead
{
mDynamicProbeCount = (U32)mProbes.size();
}
else if (sLevel == 2)
else if (LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::MANUAL_AND_TERRAIN)// <FS:Beq/> No longer required use the pipeline cached version instead
{
mDynamicProbeCount = llmax((U32)mProbes.size(), 128);
}
@ -456,13 +456,15 @@ void LLReflectionMapManager::update()
{
closestDynamic = probe;
}
if (sLevel == 0)
{
// only update default probe when coverage is set to none
llassert(probe == mDefaultProbe);
break;
}
// <FS:Beq> This code is no longer required and this update loop should self-cleanse
// However: There appears to be something that causes the reference count to be 2 for some probes that should no longer be in use.
// if (sLevel == 0)
// {
// // only update default probe when coverage is set to none
// llassert(probe == mDefaultProbe);
// break;
// }
// </FS:Beq>
}
if (realtime && closestDynamic != nullptr)
@ -489,12 +491,12 @@ void LLReflectionMapManager::update()
static LLCachedControl<F32> sUpdatePeriod(gSavedSettings, "RenderDefaultProbeUpdatePeriod", 2.f);
if ((gFrameTimeSeconds - mDefaultProbe->mLastUpdateTime) < sUpdatePeriod)
{
if (sLevel == 0)
if (LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::NONE) // <FS:Beq/> No longer required use the pipeline cached version instead
{ // when probes are disabled don't update the default probe more often than the prescribed update period
oldestProbe = nullptr;
}
}
else if (sLevel > 0)
else if (LLPipeline::sReflectionProbeLevel > (S32)LLReflectionMap::ProbeLevel::NONE) // <FS:Beq/> No longer required use the pipeline cached version instead
{ // when probes are enabled don't update the default probe less often than the prescribed update period
oldestProbe = mDefaultProbe;
}
@ -628,6 +630,12 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma
LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group)
{
// <FS:Beq> [FIRE-35070] Don't register probes if we're not using them
if( LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::NONE)
{
return nullptr;
}
// </FS:Beq>
if (!group)
{
return nullptr;
@ -648,7 +656,10 @@ LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* gr
LLReflectionMap* LLReflectionMapManager::registerViewerObject(LLViewerObject* vobj)
{
if (!LLPipeline::sReflectionProbesEnabled)
// <FS:Beq> [FIRE-35070] Don't register manual probes if we're not using them
// if (!LLPipeline::sReflectionProbesEnabled)
if (LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::NONE)
// </FS:Beq>
{
return nullptr;
}
@ -1315,7 +1326,7 @@ void LLReflectionMapManager::setUniforms()
}
void renderReflectionProbe(LLReflectionMap* probe)
void renderReflectionProbe(LLReflectionMap* probe, std::map<LLSpatialGroup*, int> groupCount, std::map<LLViewerObject*, int> objCount, std::map<F32*, int> locCount)
{
if (probe->isRelevant())
{
@ -1338,7 +1349,7 @@ void renderReflectionProbe(LLReflectionMap* probe)
gGL.end();
gGL.flush();
gGL.diffuseColor4f(1, 1, 0, 1);
gGL.diffuseColor4f(0, 1, 1, 1);
gGL.begin(gGL.LINES);
for (auto& neighbor : probe->mNeighbors)
{
@ -1350,6 +1361,44 @@ void renderReflectionProbe(LLReflectionMap* probe)
}
gGL.end();
gGL.flush();
// --- New: draw a point at the probe origin color-coded by type ---
bool dupByGroup = (probe->mGroup && groupCount[ probe->mGroup ] > 1);
bool dupByObject= (probe->mViewerObject && objCount[ probe->mViewerObject ] > 1);
bool dupByLoc = ( locCount[ probe->mOrigin.getF32ptr()] > 1);
const bool is_manual = probe->mViewerObject != nullptr;
const bool is_automatic = (probe->mGroup != nullptr) && !is_manual;
// terrain/water is when neither manual nor automatic
// const bool is_terrain = !is_manual && !is_automatic;
if (is_manual)
{
// red dot for manual probes
gGL.diffuseColor4f(1.f, 0.f, 0.f, 1.f);
}
else if (is_automatic)
{
// blue dot for automatic probes
gGL.diffuseColor4f(0.f, 0.f, 1.f, 1.f);
}
else
{
// green dot for terrain/water probes
gGL.diffuseColor4f(0.f, 1.f, 0.f, 1.f);
}
// use a bigger dot if *any* duplicate condition is true
const float normalSize = 9.f;
const float bigSize = 18.f;
float pointSize = (dupByGroup || dupByObject || dupByLoc)
? bigSize
: normalSize;
glPointSize(pointSize);
gGL.begin(gGL.POINTS);
gGL.vertex3fv(po);
gGL.end();
gGL.flush();
}
#if 0
@ -1403,10 +1452,21 @@ void renderReflectionProbe(LLReflectionMap* probe)
void LLReflectionMapManager::renderDebug()
{
gDebugProgram.bind();
std::map<LLSpatialGroup*, int> groupCount;
std::map<LLViewerObject*, int> objCount;
std::map<F32*, int> locCount;
for (LLReflectionMap* probe : mProbes)
{
if (!probe->isRelevant()) continue;
groupCount[ probe->mGroup ]++;
objCount[ probe->mViewerObject ]++;
locCount[ probe->mOrigin.getF32ptr() ]++;
}
for (auto& probe : mProbes)
{
renderReflectionProbe(probe);
renderReflectionProbe(probe, groupCount, objCount, locCount);
}
gDebugProgram.unbind();

View File

@ -43,8 +43,7 @@ class LLViewerObject;
// reflection probe mininum scale
#define LL_REFLECTION_PROBE_MINIMUM_SCALE 1.f;
void renderReflectionProbe(LLReflectionMap* probe);
void renderReflectionProbe(LLReflectionMap* probe, std::map<LLSpatialGroup*, int> groupCount, std::map<LLViewerObject*, int> objCount, std::map<F32*, int> locCount); // <FS:Beq/> enhanced metadata render for probes
class alignas(16) LLReflectionMapManager
{
LL_ALIGN_NEW

View File

@ -102,6 +102,7 @@
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
#include "rlvactions.h"
#include "rlvhandler.h"
#include "rlvlocks.h"
#include "rlvmodifiers.h"
// [/RLVa:KB]
// <FS:CR> Aurora Sim
@ -5303,6 +5304,18 @@ void LLSelectMgr::sendDetach()
return;
}
// [RLVa:KB]
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;
}
}
// [/RLVa:KB]
sendListToRegions(
"ObjectDetach",
packAgentAndSessionID,

View File

@ -742,6 +742,10 @@ bool idle_startup()
gSavedSettings.setBOOL("FSInternalShowNavbarFavoritesPanel", gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"));
// </FS:Ansariel>
// <FS:Ansariel> Added to determine if toolbar gets hidden when empty
if (gToolBarView)
gToolBarView->setHideBottomOnEmpty(FSCommon::isLegacySkin());
if (LLFeatureManager::getInstance()->isSafe())
{
LLNotificationsUtil::add("DisplaySetToSafe");
@ -2910,9 +2914,6 @@ bool idle_startup()
do_startup_frame();
// We're successfully logged in.
gSavedSettings.setBOOL("FirstLoginThisInstall", false);
LLFloaterReg::showInitialVisibleInstances();
LLFloaterGridStatus::getInstance()->startGridStatusTimer();
@ -3342,6 +3343,30 @@ bool idle_startup()
LLPerfStats::StatsRecorder::setAutotuneInit();
// Display Avatar Welcome Pack the first time a user logs in
// (or clears their settings....)
if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
{
LLFloater* avatar_welcome_pack_floater = LLFloaterReg::findInstance("avatar_welcome_pack");
if (avatar_welcome_pack_floater != nullptr)
{
// There is a (very - 1 in ~50 times) hard to repro bug where the login
// page is not hidden when the AWP floater is presented. This (agressive)
// approach to always close it seems like the best fix for now.
// <FS:Ansariel> [FS Login Panel]
//LLPanelLogin::closePanel();
FSPanelLogin::closePanel();
// </FS:Ansariel> [FS Login Panel]
avatar_welcome_pack_floater->setVisible(true);
}
}
//// We're successfully logged in.
// 2025-06 Moved lower down in the state machine so the Avatar Welcome Pack
// floater display can be triggered correctly.
gSavedSettings.setBOOL("FirstLoginThisInstall", false);
// <FS:Techwolf Lupindo> FIRE-6643 Display MOTD when login screens are disabled
if (gSavedSettings.getBOOL("FSDisableLoginScreens"))
{

View File

@ -1826,7 +1826,9 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
mTextDisabledColor(p.text_disabled_color), // <FS:Zi> Add label/caption colors
mLabel(p.label), // <FS:Zi> FIRE-34300 - Fix label not showing in texture picker floater title
// <FS:Ansariel> Mask texture if desired
mIsMasked(false)
mIsMasked(false),
// <FS:TJ> [FIRE-35544] For disabling texture previews for no-mod materials
mIsPreviewDisabled(false)
{
mCaptionHeight = p.show_caption ? BTN_HEIGHT_SMALL : 0; // <FS:Zi> leave some room underneath the image for the caption
// Default of defaults is white image for diff tex
@ -1992,7 +1994,7 @@ void LLTextureCtrl::setEnabled( bool enabled )
// <FS:Ansariel> Texture preview mode
//LLView::setEnabled( enabled );
LLView::setEnabled( (enabled || getValue().asUUID().notNull()) );
LLView::setEnabled(enabled || (getValue().asUUID().notNull() && !mIsPreviewDisabled));
mOpenTexPreview = !enabled;
// </FS:Ansariel>
}
@ -2664,7 +2666,7 @@ void LLTextureCtrl::setValue( const LLSD& value )
//setImageAssetID(value.asUUID());
LLUUID uuid = value.asUUID();
setImageAssetID(uuid);
LLView::setEnabled( (!mOpenTexPreview || uuid.notNull()) );
LLView::setEnabled(!mOpenTexPreview || (uuid.notNull() && !mIsPreviewDisabled));
// </FS:Ansariel>
}

View File

@ -264,6 +264,8 @@ public:
// <FS:Ansariel> Mask texture if desired
void setIsMasked(bool masked) { mIsMasked = masked; }
// <FS:TJ> [FIRE-35544] For disabling texture previews for no-mod materials
void setIsPreviewDisabled(bool is_preview_disabled) { mIsPreviewDisabled = is_preview_disabled; }
void setLabelColor(const LLColor4& c) { mTextEnabledColor = c; updateLabelColor(); } // <FS:Zi> Add label/caption colors
void setDisabledLabelColor(const LLColor4& c) { mTextDisabledColor = c; updateLabelColor(); } // <FS:Zi> Add label/caption colors
@ -315,6 +317,8 @@ private:
// <FS:Ansariel> Mask texture if desired
bool mIsMasked;
// <FS:TJ> [FIRE-35544] For disabling texture previews for no-mod materials
bool mIsPreviewDisabled;
LLUIColor mTextEnabledColor; // <FS:Zi> Add label/caption colors
LLUIColor mTextDisabledColor; // <FS:Zi> Add label/caption colors

View File

@ -713,7 +713,7 @@ void LLGLTexMemBar::draw()
//text = llformat("Textures: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d RAW:%d HTP:%d DEC:%d CRE:%d ",
text = llformat("Tex: %d Fetch: %d(%d) Pkts:%d(%d) CAC R/W: %d/%d LFS:%d RAW:%d HTP:%d DEC:%d CRE:%d FCA:%d ",
// </FS:Ansariel>
// <FS:minerjr> Fixed up the missing variables and converted 64bit size_t's to S32's to allow proper numbers to appear
// <FS:minerjr> Fixed up the missing variables and converted 64bit size_t's to S32's to allow proper numbers to appear
gTextureList.getNumImages(),
LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(),
LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount,
@ -727,7 +727,7 @@ void LLGLTexMemBar::draw()
(S32)gTextureList.mCreateTextureList.size(),
(S32)gTextureList.mFastCacheList.size());
// </FS:Ansariel>
// </FS:minerjr>
// </FS:minerjr>
x_right = 550.0f;
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0.f, (F32)(v_offset + line_height*3),
text_color, LLFontGL::LEFT, LLFontGL::TOP,

View File

@ -131,9 +131,6 @@ bool LLToolBarView::postBuild()
// <FS:Ansariel> Member variable needed for console chat bottom offset
mBottomChatStack = findChild<LLView>("bottom_chat_stack");
// <FS:Ansariel> Added to determine if toolbar gets hidden when empty
mHideBottomOnEmpty = FSCommon::isLegacySkin();
return true;
}

View File

@ -102,9 +102,12 @@ public:
bool isModified() const;
// <FS:Ansariel> Getters for member variables needed for console chat bottom offset
LLView* getBottomChatStack() const { return mBottomChatStack; };
LLView* getBottomChatStack() const { return mBottomChatStack; }
// </FS:Ansariel>
// <FS:Ansariel> Added to determine if toolbar gets hidden when empty
void setHideBottomOnEmpty(bool hideBottomOnEmpty) { mHideBottomOnEmpty = hideBottomOnEmpty; }
protected:
friend class LLUICtrlFactory;
LLToolBarView(const Params&);

View File

@ -38,8 +38,8 @@
#include "llfloateraddpaymentmethod.h"
#include "llfloaterauction.h"
#include "llfloaterautoreplacesettings.h"
#include "llfloateravatar.h"
#include "llfloateravatarpicker.h"
#include "llfloateravatarwelcomepack.h"
//#include "llfloateravatarrendersettings.h" // <FS:Ansariel> [FS Persisted Avatar Render Settings]
#include "llfloateravatartextures.h"
#include "llfloaterbanduration.h"
@ -399,8 +399,8 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
LLFloaterReg::add("associate_listing", "floater_associate_listing.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAssociateListing>);
LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAuction>);
LLFloaterReg::add("avatar", "floater_avatar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatar>);
LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarPicker>);
LLFloaterReg::add("avatar_welcome_pack", "floater_avatar_welcome_pack.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarWelcomePack>);
// <FS:Ansariel> [FS Persisted Avatar Render Settings]
//LLFloaterReg::add("avatar_render_settings", "floater_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarRenderSettings>);
LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAvatarTextures>);

View File

@ -3327,7 +3327,7 @@ void derenderObject(bool permanent)
asset_type = LLAssetType::AT_OBJECT;
}
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(id, entry_name, region_name, asset_type, permanent, false);
FSAssetBlacklist::getInstance()->addNewItemToBlacklist(id, entry_name, region_name, asset_type, FSAssetBlacklist::eBlacklistFlag::NONE, permanent, false);
if (permanent)
{
@ -3476,6 +3476,15 @@ void handle_object_tex_refresh(LLViewerObject* object, LLSelectNode* node)
LLViewerTexture* spec_img = object->getTESpecularMap(i);
faces_per_texture[spec_img->getID()].push_back(i);
}
LLPointer<LLGLTFMaterial> mat = object->getTE(i)->getGLTFRenderMaterial();
if (mat.notNull())
{
for (U32 j = 0; j < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++j)
{
faces_per_texture[mat->mTextureId[j]].push_back(i);
}
}
}
map_t::iterator it;

View File

@ -4700,6 +4700,38 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data)
(void)sun_direction, (void)moon_direction, (void)phase;
}
// <FS> Sound blacklist
static bool is_sound_blacklisted(const LLUUID& sound_id, const LLUUID& object_id, const LLUUID& owner_id)
{
FSAssetBlacklist& blacklist = FSAssetBlacklist::instance();
if (blacklist.isBlacklisted(sound_id, LLAssetType::AT_SOUND))
{
return true;
}
else if (object_id == owner_id)
{
// Gesture sound
return blacklist.isBlacklisted(owner_id, LLAssetType::AT_SOUND, FSAssetBlacklist::eBlacklistFlag::GESTURE);
}
else if (LLViewerObject* object = gObjectList.findObject(object_id))
{
if (object->isAttachment())
{
// Attachment sound
return blacklist.isBlacklisted(owner_id, LLAssetType::AT_SOUND, FSAssetBlacklist::eBlacklistFlag::WORN);
}
else
{
// Rezzed object sound
return blacklist.isBlacklisted(owner_id, LLAssetType::AT_SOUND, FSAssetBlacklist::eBlacklistFlag::REZZED);
}
}
return false;
}
// </FS>
void process_sound_trigger(LLMessageSystem *msg, void **)
{
if (!gAudiop)
@ -4728,10 +4760,8 @@ void process_sound_trigger(LLMessageSystem *msg, void **)
// </FS:ND>
// <FS> Asset blacklist
if (FSAssetBlacklist::getInstance()->isBlacklisted(sound_id, LLAssetType::AT_SOUND))
{
if (is_sound_blacklisted(sound_id, object_id, owner_id))
return;
}
// </FS>
// NaCl - Antispam Registry
@ -4837,11 +4867,14 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data)
msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
// <FS> Asset blacklist
if (FSAssetBlacklist::getInstance()->isBlacklisted(sound_id, LLAssetType::AT_SOUND))
{
// <FS:ND> Protect against corrupted sounds
if (gAudiop->isCorruptSound(sound_id))
return;
// </FS:ND>
// <FS> Asset blacklist
if (is_sound_blacklisted(sound_id, object_id, owner_id))
return;
}
// </FS>
// NaCl - Antispam Registry
@ -4853,12 +4886,7 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data)
}
// NaCl End
// <FS:ND> Protect against corrupted sounds
if( gAudiop->isCorruptSound( sound_id ) )
return;
// </FS:ND>
LLViewerObject *objectp = gObjectList.findObject(object_id);
LLViewerObject* objectp = gObjectList.findObject(object_id);
if (!objectp) return;
if (LLMuteList::getInstance()->isMuted(object_id)) return;
@ -4894,11 +4922,14 @@ void process_attached_sound(LLMessageSystem *msg, void **user_data)
msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
// <FS> Asset blacklist
if (FSAssetBlacklist::getInstance()->isBlacklisted(sound_id, LLAssetType::AT_SOUND))
{
// <FS:ND> Protect against corrupted sounds
if (gAudiop->isCorruptSound(sound_id))
return;
// </FS:ND>
// <FS> Asset blacklist
if (is_sound_blacklisted(sound_id, object_id, owner_id))
return;
}
// </FS>
// NaCl - Antispam Registry

View File

@ -434,7 +434,7 @@ void LLGridManager::setGridChoice(const std::string& grid)
}
}
std::string LLGridManager::getGrid( const std::string &grid )
std::string LLGridManager::getGrid( const std::string &grid ) const
{
std::string grid_name;
@ -446,7 +446,7 @@ std::string LLGridManager::getGrid( const std::string &grid )
else
{
// search the grid list for a grid with a matching id
for(LLSD::map_iterator grid_iter = mGridList.beginMap();
for(LLSD::map_const_iterator grid_iter = mGridList.beginMap();
grid_name.empty() && grid_iter != mGridList.endMap();
grid_iter++)
{
@ -642,12 +642,12 @@ void LLGridManager::updateIsInProductionGrid()
}
}
bool LLGridManager::isInProductionGrid()
bool LLGridManager::isInProductionGrid() const
{
return mIsInProductionGrid;
}
bool LLGridManager::isSystemGrid(const std::string& grid)
bool LLGridManager::isSystemGrid(const std::string& grid) const
{
std::string grid_name = getGrid(grid);

View File

@ -95,7 +95,7 @@ class LLGridManager : public LLSingleton<LLGridManager>
* descriptive form (it is used in the login panel grid menu, for example).
*/
/// Return the name of a grid, given either its name or its id
std::string getGrid( const std::string &grid );
std::string getGrid( const std::string &grid ) const;
/// Get the id (short form selector) for a given grid
std::string getGridId(const std::string& grid);
@ -206,13 +206,13 @@ class LLGridManager : public LLSingleton<LLGridManager>
//@}
/// Is the given grid one of the hard-coded default grids (Agni or Aditi)
bool isSystemGrid(const std::string& grid);
bool isSystemGrid(const std::string& grid) const;
/// Is the selected grid one of the hard-coded default grids (Agni or Aditi)
bool isSystemGrid() { return isSystemGrid(mGrid); }
bool isSystemGrid() const { return isSystemGrid(mGrid); }
//<FS:AW compatibility with opensim api>
/// Is the selected grid Second Life Main grid?
bool isInSLMain() { return isInProductionGrid(); }
bool isInSLMain() const { return isInProductionGrid(); }
/**
* the purpose of not just taking isInProductionGrid() is to
* create merge conflicts so that changes that need special casing
@ -220,12 +220,12 @@ class LLGridManager : public LLSingleton<LLGridManager>
*/
/// Is the selected grid a Second Life beta grid?
bool isInSLBeta() { return (isSystemGrid() && !isInProductionGrid()); }
bool isInSecondLife() { return (isInSLMain() || isInSLBeta()); } // <FS:CR>
bool isInSLBeta() const { return (isSystemGrid() && !isInProductionGrid()); }
bool isInSecondLife() const { return (isInSLMain() || isInSLBeta()); } // <FS:CR>
private:
//</FS:AW compatibility with opensim api>
/// Is the selected grid a production grid?
bool isInProductionGrid();
bool isInProductionGrid() const;
/**
* yes, that's not a very helpful description.
* I don't really know why that is different from isSystemGrid()

View File

@ -6605,13 +6605,6 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow
return;
}
// <FS:Ansariel> Asset blacklist
if (FSAssetBlacklist::getInstance()->isBlacklisted(audio_uuid, LLAssetType::AT_SOUND))
{
return;
}
// </FS:Ansariel>
if (flags & LL_SOUND_FLAG_LOOP
&& mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData()
&& mAudioSourcep->getCurrentData()->getID() == audio_uuid)

View File

@ -1357,6 +1357,12 @@ U32 LLViewerRegion::getNumOfVisibleGroups() const
void LLViewerRegion::updateReflectionProbes(bool full_update)
{
// [FIRE-35070] Don't update reflection probes if disabled
if (LLPipeline::sReflectionProbeLevel == (S32)LLReflectionMap::ProbeLevel::NONE)
{
return; // no probes
}
// </FS:Beq>
if (!full_update && mReflectionMaps.empty())
{
return;

View File

@ -380,7 +380,7 @@ public:
// </FS:CR>
#ifdef OPENSIM
std::set<std::string> getGods() { return mGodNames; };
const std::set<std::string, std::less<>>& getGods() const { return mGodNames; };
#endif // OPENSIM
// </FS:CR>
@ -624,7 +624,7 @@ public:
// <FS:CR> Opensim region capabilities
#ifdef OPENSIM
std::set<std::string> mGodNames;
std::set<std::string, std::less<>> mGodNames;
#endif
// </FS:CR>

View File

@ -420,7 +420,7 @@ void LLViewerTextureList::dump()
LL_CONT << image->getNumVolumes(index) << " ";
}
// </FS:minerjr> [FIRE-35081]
LL_CONT << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
LL_CONT << " " << image->getID().asString().substr(0, 7)
<< LL_ENDL;
// <FS:minerjr> [FIRE-35081] Blurry prims not changing with graphics settings
image_counts[(image->getDiscardLevel() + 1)] += 1; // Need to add +1 to make up for -1 being a possible value
@ -1498,6 +1498,10 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
// <FS:Ansariel> Fast cache stats
sNumFastCacheReads++;
// </FS:Ansariel>
// <FS:Ansariel> Fix fast cache
if (timer.getElapsedTimeF32() > max_time)
break;
// </FS:Ansariel>
}
mFastCacheList.erase(mFastCacheList.begin(), enditer);
return timer.getElapsedTimeF32();
@ -1609,7 +1613,9 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
LLTimer timer;
//loading from fast cache
updateImagesLoadingFastCache(max_time);
// <FS:Ansariel> Fix fast cache
//updateImagesLoadingFastCache(max_time);
max_time -= updateImagesLoadingFastCache(max_time);
// Update texture stats and priorities
std::vector<LLPointer<LLViewerFetchedTexture> > image_list;

View File

@ -2503,13 +2503,13 @@ void LLViewerWindow::initWorldUI()
// url = LLWeb::expandURLSubstitutions(url, LLSD());
// destinations->navigateTo(url, "text/html");
// }
// LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
// if (avatar_picker)
// LLMediaCtrl* avatar_welcome_pack = LLFloaterReg::getInstance("avatar_welcome_pack")->findChild<LLMediaCtrl>("avatar_picker_contents");
// if (avatar_welcome_pack)
// {
// avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
// std::string url = gSavedSettings.getString("AvatarPickerURL");
// avatar_welcome_pack->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
// std::string url = gSavedSettings.getString("AvatarWelcomePack");
// url = LLWeb::expandURLSubstitutions(url, LLSD());
// avatar_picker->navigateTo(url, "text/html");
// avatar_welcome_pack->navigateTo(url, "text/html");
// }
std::string destination_guide_url;
#ifdef OPENSIM // <FS:AW optional opensim support>
@ -2550,18 +2550,18 @@ void LLViewerWindow::initWorldUI()
else
#endif // OPENSIM // <FS:AW optional opensim support>
{
avatar_picker_url = gSavedSettings.getString("AvatarPickerURL");
avatar_picker_url = gSavedSettings.getString("AvatarWelcomePack");
}
if(!avatar_picker_url.empty())
{
LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
if (avatar_picker)
LLMediaCtrl* avatar_welcome_pack = LLFloaterReg::getInstance("avatar_welcome_pack")->findChild<LLMediaCtrl>("avatar_picker_contents");
if (avatar_welcome_pack)
{
avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
avatar_welcome_pack->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
avatar_picker_url = LLWeb::expandURLSubstitutions(avatar_picker_url, LLSD());
LL_DEBUGS("WebApi") << "AvatarPickerURL \"" << avatar_picker_url << "\"" << LL_ENDL;
avatar_picker->navigateTo(avatar_picker_url, HTTP_CONTENT_TEXT_HTML);
avatar_welcome_pack->navigateTo(avatar_picker_url, HTTP_CONTENT_TEXT_HTML);
}
}
// </FS:AW opensim destinations and avatar picker>
@ -7338,11 +7338,16 @@ void LLViewerWindow::setUIVisibility(bool visible)
// LLPanelTopInfoBar::getInstance()->setVisible(visible? gSavedSettings.getBOOL("ShowMiniLocationPanel") : false);
mStatusBarContainer->setVisible(visible);
// <FS:Zi> hide utility bar if we are on a skin that uses it, e.g. Vintage
LLView* utilityBarStack = mRootView->findChildView("chat_bar_utility_bar_stack");
if (utilityBarStack)
// <FS:Zi> hide utility bar if we are on a skin that uses it, i.e. Vintage
// Beq Note: Added a skin check to fix FIRE-29517 "hitch when entering mouselook"
// This was caused having to search for a non-existent childview. If another skin other than vintage
// ever needs chat_bar_utility_bar_stack in the future, this will need to be updated.
if (FSCommon::isLegacySkin())
{
utilityBarStack->setVisible(visible);
if (LLView* utilityBarStack = mRootView->findChildView("chat_bar_utility_bar_stack"); utilityBarStack)
{
utilityBarStack->setVisible(visible);
}
}
// </FS:Zi>
}

View File

@ -238,6 +238,17 @@ enum ERenderName
RENDER_NAME_FADE
};
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// Different settings based on FSImpostorAvatarExclude
enum EImpostorAvatarExclude
{
NONE, // Default, no avatar excluded
USER, // Check for mIsAnimesh only, exclude user Avatar's which are Animesh or have Animesh attachments
CONTROL, // Check for mIsControlAvatar only, exclude control avatars (avtars which don't have a user UUID assigned)
BOTH // Check both mIsAnimesh or mIsControlAvatar, exclude both User Amimesh and Control avatars.
};
// </FS:minerjr> [FIRE-35735]
#define JELLYDOLLS_SHOULD_IMPOSTOR
//-----------------------------------------------------------------------------
@ -4643,6 +4654,9 @@ bool LLVOAvatar::isVisuallyMuted()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // <FS:Beq/> Tracy accounting for imposter testing.
bool muted = false;
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// </FS:minerjr> [FIRE-35735]
// <FS:Ansariel> FIRE-11783: Always visually mute avatars that are muted
if (!isSelf() && isInMuteList())
@ -4677,6 +4691,13 @@ bool LLVOAvatar::isVisuallyMuted()
#else
muted = false;
#endif
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If the avatar is set to be excluded, set the muted flag to false
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
muted = false;
}
// </FS:minerjr> [FIRE-35735]
}
// <FS:Ansariel> FIRE-11783: Always visually mute avatars that are muted
//else if (isInMuteList())
@ -4686,10 +4707,26 @@ bool LLVOAvatar::isVisuallyMuted()
// </FS:Ansariel>
else if (mIsControlAvatar)
{
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If the avatar is set to control or both, set the the meted flag to false
if (impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL)
{
muted = false;
}
else
// </FS:minerjr> [FIRE-35735]
muted = isTooSlow();
}
else
{
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If the avatar is an animesh and the FSImpostorAvatarExclude is either a USER or BOTH (Can use & as both 1 and 3 have 1 set)
if ((impostor_avatar_exclude & EImpostorAvatarExclude::USER) && mIsAnimesh)
{
muted = false;
}
else
// </FS:minerjr> [FIRE-35735]
muted = isTooComplex(); // <FS:Beq/> this should not trigger based on perfstats
}
}
@ -7608,6 +7645,10 @@ void LLVOAvatar::updateAttachmentOverrides()
}
}
#endif
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
}
void LLVOAvatar::notifyAttachmentMeshLoaded()
@ -8558,6 +8599,10 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
updateMeshVisibility();
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
return attachment;
}
@ -8883,6 +8928,10 @@ bool LLVOAvatar::detachObject(LLViewerObject *viewer_object)
}
updateMeshVisibility();
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL;
return true;
@ -8893,6 +8942,10 @@ bool LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (iter != mPendingAttachment.end())
{
mPendingAttachment.erase(iter);
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// If either the main body of the avatar is animated, or there are any animated attachedments, then flag it as an Animesh.
mIsAnimesh = getNumAnimatedObjectAttachments() > 0 || isAnimatedObject();
// </FS:minerjr> [FIRE-35735]
return true;
}
@ -9679,6 +9732,15 @@ bool LLVOAvatar::isTooComplex() const
}
else
{
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// If the avatar is set to be excluded, return that the avatar is not too complex
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
return false;
}
// </FS:minerjr> [FIRE-35735]
// Determine if visually muted or not
static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U);
static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
@ -12118,8 +12180,23 @@ bool LLVOAvatar::isImpostor()
{
// <FS:Beq> render time handling using tooSlow()
// return isVisuallyMuted() || (sLimitNonImpostors && (mUpdatePeriod > 1));
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// Store the result of is visually muted as used in possibly 2 places
bool is_visual_muted = isVisuallyMuted();
// If the avatar is set to be excluded, return that the avatar is not an Impostor
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
return false;
}
// </FS:minerjr> [FIRE-35735]
return (
isVisuallyMuted() ||
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
// isVisuallyMuted() ||
is_visual_muted || // Save from calling isVisuallyMuted a second time
// </FS:minerjr> [FIRE-35735]
isTooSlowWithoutShadows() ||
(sLimitNonImpostors && (mUpdatePeriod > 1) )
);
@ -12140,6 +12217,15 @@ bool LLVOAvatar::shouldImpostor(const F32 rank_factor)
// return sLimitNonImpostors && (mVisibilityRank > sMaxNonImpostors * rank_factor);
// static LLCachedControl<bool> render_jellys_As_imposters(gSavedSettings, "RenderJellyDollsAsImpostors");
// <FS:minerjr> [FIRE-35735] Imposter/Impostor Avatar Exclusions
static LLCachedControl<U32> impostor_avatar_exclude(gSavedSettings,"FSImpostorAvatarExclude", 0);
// If the avatar is set to be excluded, return that the avatar should not be impostored
if ((mIsControlAvatar && impostor_avatar_exclude >= EImpostorAvatarExclude::CONTROL) || (mIsAnimesh && (impostor_avatar_exclude & EImpostorAvatarExclude::USER)))
{
return false;
}
// </FS:minerjr> [FIRE-35735]
if (isTooSlowWithoutShadows())
{
return true;

View File

@ -685,6 +685,7 @@ public:
// [/RLVa:KB]
// bool mNeedsImpostorUpdate;
S32 mLastImpostorUpdateReason;
bool mIsAnimesh; // <FS:minerjr> FIRE-35735: Imposter/Impostor Avatar Exclusions (Flag to track if avatar or attachments have Animated Mesh flagged)
F32SecondsImplicit mLastImpostorUpdateFrameTime;
const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; }
void setNeedsExtentUpdate(bool val) { mNeedsExtentUpdate = val; }

View File

@ -225,8 +225,7 @@ void PermissionsTracker::objectPropertiesCallback(LLMessageSystem* msg)
mPermissionsList[source_id].objectName = object_name;
mPermissionsList[source_id].ownerID = object_owner;
LLAvatarName avatar_name;
if (LLAvatarNameCache::get(object_owner, &avatar_name))
if (LLAvatarName avatar_name; LLAvatarNameCache::get(object_owner, &avatar_name))
{
LL_DEBUGS("PermissionsTracker") << "Found cached entry for owner " << object_owner.asString()
<< ": " << avatar_name.getCompleteName() << LL_ENDL;
@ -234,10 +233,8 @@ void PermissionsTracker::objectPropertiesCallback(LLMessageSystem* msg)
}
else if (mAvatarNameCacheConnections.find(object_owner) != mAvatarNameCacheConnections.end())
{
boost::signals2::connection cb_connection = LLAvatarNameCache::get(object_owner, boost::bind(&PermissionsTracker::avatarNameCallback, this, _1, _2));
mAvatarNameCacheConnections.insert(std::make_pair(object_owner, cb_connection));
LL_DEBUGS("PermissionsTracker") << "Requesting avatar name for owner " << object_owner.asString() << LL_ENDL;
mAvatarNameCacheConnections.try_emplace(object_owner, LLAvatarNameCache::get(object_owner, boost::bind(&PermissionsTracker::avatarNameCallback, this, _1, _2)));
}
}
}

View File

@ -352,6 +352,7 @@ bool LLPipeline::sRenderAttachedLights = true;
bool LLPipeline::sRenderAttachedParticles = true;
bool LLPipeline::sRenderDeferred = false;
bool LLPipeline::sReflectionProbesEnabled = false;
S32 LLPipeline::sReflectionProbeLevel = (S32)LLReflectionMap::ProbeLevel::NONE; // <FS:Beq/> [FIRE-35070] Address progressive FPS loss.
S32 LLPipeline::sVisibleLightCount = 0;
bool LLPipeline::sRenderingHUDs;
F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f;
@ -1262,8 +1263,10 @@ void LLPipeline::refreshCachedSettings()
RenderMirrors = gSavedSettings.getBOOL("RenderMirrors");
RenderHeroProbeUpdateRate = gSavedSettings.getS32("RenderHeroProbeUpdateRate");
RenderHeroProbeConservativeUpdateMultiplier = gSavedSettings.getS32("RenderHeroProbeConservativeUpdateMultiplier");
sReflectionProbesEnabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionsEnabled") && gSavedSettings.getBOOL("RenderReflectionsEnabled");
// <FS:Beq> [FIRE-35070] Instead of using the above we'll add a new static level variable to save some lookups. Making the above "work" with ProbeLevel will break everything.
sReflectionProbeLevel = gSavedSettings.getS32("RenderReflectionProbeLevel");
// <FS:Beq/>
RenderSpotLight = nullptr;
if (gNonInteractive)

View File

@ -690,6 +690,9 @@ public:
static bool sRenderAttachedParticles;
static bool sRenderDeferred;
static bool sReflectionProbesEnabled;
// <FS:Beq> [FIRE-35070] Address gradual slowdown issue
static S32 sReflectionProbeLevel;
// </FS:Beq>
static S32 sVisibleLightCount;
static bool sRenderingHUDs;
static F32 sDistortionWaterClipPlaneMargin;

View File

@ -14,8 +14,8 @@
</array>
<key>rotation</key>
<array>
<real>0.07227716594934463500976562</real>
<real>0.2199114710092544555664062</real>
<real>0.072256624698638916015625</real>
<real>0.2199114412069320678710938</real>
<real>0.2693966925144195556640625</real>
</array>
<key>scale</key>
@ -39,9 +39,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.05256520584225654602050781</real>
<real>0.1256637275218963623046875</real>
<real>-0.4665162861347198486328125</real>
<real>-0.072256624698638916015625</real>
<real>0.2199114412069320678710938</real>
<real>-0.2693966925144195556640625</real>
</array>
<key>scale</key>
<array>
@ -64,9 +64,9 @@
</array>
<key>rotation</key>
<array>
<real>0.03285326063632965087890625</real>
<real>1.455191696309032778344772e-11</real>
<real>-0.01314130239188671112060547</real>
<real>0.03281218931078910827636719</real>
<real>1.455191522836685180664062e-11</real>
<real>-0.01314130332320928573608398</real>
</array>
<key>scale</key>
<array>
@ -89,9 +89,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.03285326063632965087890625</real>
<real>1.455191696309032778344772e-11</real>
<real>0.01314130239188671112060547</real>
<real>-0.03281218931078910827636719</real>
<real>1.455191522836685180664062e-11</real>
<real>0.01314130332320928573608398</real>
</array>
<key>scale</key>
<array>
@ -114,7 +114,7 @@
</array>
<key>rotation</key>
<array>
<real>0.01971195824444293975830078</real>
<real>0.01972222141921520233154297</real>
<real>0</real>
<real>0</real>
</array>
@ -139,7 +139,7 @@
</array>
<key>rotation</key>
<array>
<real>-0.01971195824444293975830078</real>
<real>-0.01972222141921520233154297</real>
<real>0</real>
<real>0</real>
</array>
@ -164,9 +164,9 @@
</array>
<key>rotation</key>
<array>
<real>0.04599455744028091430664062</real>
<real>-4.65661342818890489070327e-10</real>
<real>0.06570650637149810791015625</real>
<real>0.04607669264078140258789062</real>
<real>-2.3283064365386962890625e-10</real>
<real>0.0657065212726593017578125</real>
</array>
<key>scale</key>
<array>
@ -189,9 +189,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.09855977445840835571289062</real>
<real>0</real>
<real>0.006570650730282068252563477</real>
<real>-0.04607669264078140258789062</real>
<real>-2.3283064365386962890625e-10</real>
<real>-0.0657065212726593017578125</real>
</array>
<key>scale</key>
<array>
@ -214,7 +214,7 @@
</array>
<key>rotation</key>
<array>
<real>0.03285325691103935241699219</real>
<real>0.03281219303607940673828125</real>
<real>0</real>
<real>0</real>
</array>
@ -239,7 +239,7 @@
</array>
<key>rotation</key>
<array>
<real>-0.03285325691103935241699219</real>
<real>-0.03281219303607940673828125</real>
<real>0</real>
<real>0</real>
</array>
@ -264,8 +264,8 @@
</array>
<key>rotation</key>
<array>
<real>0.01971195638179779052734375</real>
<real>2.910383392618065556689544e-11</real>
<real>0.0197222232818603515625</real>
<real>-8.731149137020111083984375e-11</real>
<real>-0.04599456489086151123046875</real>
</array>
<key>scale</key>
@ -289,8 +289,8 @@
</array>
<key>rotation</key>
<array>
<real>-0.01971195638179779052734375</real>
<real>2.910383392618065556689544e-11</real>
<real>-0.0197222232818603515625</real>
<real>-8.731149137020111083984375e-11</real>
<real>0.04599456489086151123046875</real>
</array>
<key>scale</key>
@ -314,9 +314,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.749054372310638427734375</real>
<real>-0.749095380306243896484375</real>
<real>-0.543495595455169677734375</real>
<real>-0.913320600986480712890625</real>
<real>-0.91332066059112548828125</real>
</array>
<key>scale</key>
<array>
@ -339,9 +339,9 @@
</array>
<key>rotation</key>
<array>
<real>-1.42372357845306396484375</real>
<real>-0.589437425136566162109375</real>
<real>-0.1377763897180557250976562</real>
<real>0.749095380306243896484375</real>
<real>-0.543495595455169677734375</real>
<real>0.91332066059112548828125</real>
</array>
<key>scale</key>
<array>
@ -365,8 +365,8 @@
<key>rotation</key>
<array>
<real>-2.0171897411346435546875</real>
<real>-1.099557399749755859375</real>
<real>-0.64392375946044921875</real>
<real>-1.09955728054046630859375</real>
<real>-0.643852174282073974609375</real>
</array>
<key>scale</key>
<array>
@ -389,9 +389,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.03942390903830528259277344</real>
<real>0.03141593188047409057617188</real>
<real>0.03285326063632965087890625</real>
<real>2.0171897411346435546875</real>
<real>-1.09955728054046630859375</real>
<real>0.643852174282073974609375</real>
</array>
<key>scale</key>
<array>
@ -415,8 +415,8 @@
<key>rotation</key>
<array>
<real>-0.558505475521087646484375</real>
<real>-0.56548678874969482421875</real>
<real>-0.05256522819399833679199219</real>
<real>-0.565486729145050048828125</real>
<real>-0.05253438279032707214355469</real>
</array>
<key>scale</key>
<array>
@ -439,9 +439,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.0131413042545318603515625</real>
<real>5.820767479125521504101926e-11</real>
<real>-0.1051304414868354797363281</real>
<real>0.558505475521087646484375</real>
<real>-0.565486729145050048828125</real>
<real>0.05253438279032707214355469</real>
</array>
<key>scale</key>
<array>
@ -464,9 +464,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.987495481967926025390625</real>
<real>0.01987109147012233734130859</real>
<real>-0.498646259307861328125</real>
<real>-0.987507343292236328125</real>
<real>0.01987109519541263580322266</real>
<real>-0.498646318912506103515625</real>
</array>
<key>scale</key>
<array>
@ -489,9 +489,9 @@
</array>
<key>rotation</key>
<array>
<real>-1.4442241191864013671875</real>
<real>-0.281714916229248046875</real>
<real>-0.3864487111568450927734375</real>
<real>0.987507343292236328125</real>
<real>0.01987109519541263580322266</real>
<real>0.498646318912506103515625</real>
</array>
<key>scale</key>
<array>
@ -514,9 +514,9 @@
</array>
<key>rotation</key>
<array>
<real>-1.96462452411651611328125</real>
<real>-1.9645426273345947265625</real>
<real>-0.4084071218967437744140625</real>
<real>-0.551934778690338134765625</real>
<real>-0.551934719085693359375</real>
</array>
<key>scale</key>
<array>
@ -539,9 +539,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.03285326063632965087890625</real>
<real>2.910383392618065556689544e-11</real>
<real>-0.01971195451915264129638672</real>
<real>1.9645426273345947265625</real>
<real>-0.4084071218967437744140625</real>
<real>0.551934719085693359375</real>
</array>
<key>scale</key>
<array>
@ -564,7 +564,7 @@
</array>
<key>rotation</key>
<array>
<real>-0.2431140989065170288085938</real>
<real>-0.24312436580657958984375</real>
<real>0</real>
<real>-0.0722771584987640380859375</real>
</array>
@ -589,9 +589,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.01971195451915264129638672</real>
<real>7.27595848154516389172386e-12</real>
<real>0.006570650730282068252563477</real>
<real>0.24312436580657958984375</real>
<real>0</real>
<real>0.0722771584987640380859375</real>
</array>
<key>scale</key>
<array>
@ -615,8 +615,8 @@
<key>rotation</key>
<array>
<real>-0.1576956808567047119140625</real>
<real>1.07128322124481201171875</real>
<real>0.1379837095737457275390625</real>
<real>1.0712833404541015625</real>
<real>0.1380554884672164916992188</real>
</array>
<key>scale</key>
<array>
@ -639,9 +639,9 @@
</array>
<key>rotation</key>
<array>
<real>0.01314130239188671112060547</real>
<real>0</real>
<real>0.006570651195943355560302734</real>
<real>0.1576956808567047119140625</real>
<real>1.0712833404541015625</real>
<real>-0.1380554884672164916992188</real>
</array>
<key>scale</key>
<array>
@ -664,9 +664,9 @@
</array>
<key>rotation</key>
<array>
<real>-1.32070124149322509765625</real>
<real>1.22522127628326416015625</real>
<real>1.018451213836669921875</real>
<real>-1.32070100307464599609375</real>
<real>1.2252213954925537109375</real>
<real>1.0183994770050048828125</real>
</array>
<key>scale</key>
<array>
@ -689,9 +689,9 @@
</array>
<key>rotation</key>
<array>
<real>0.03942390531301498413085938</real>
<real>5.82076609134674072265625e-11</real>
<real>-0.01971195451915264129638672</real>
<real>1.32070100307464599609375</real>
<real>1.2252213954925537109375</real>
<real>-1.0183994770050048828125</real>
</array>
<key>scale</key>
<array>
@ -714,9 +714,9 @@
</array>
<key>rotation</key>
<array>
<real>-0.597929298877716064453125</real>
<real>-0.59792935848236083984375</real>
<real>-0.251327455043792724609375</real>
<real>-0.08541848510503768920898438</real>
<real>-0.08534660190343856811523438</real>
</array>
<key>scale</key>
<array>
@ -739,9 +739,9 @@
</array>
<key>rotation</key>
<array>
<real>0.03285325691103935241699219</real>
<real>0</real>
<real>-0</real>
<real>0.59792935848236083984375</real>
<real>-0.251327455043792724609375</real>
<real>0.08534660190343856811523438</real>
</array>
<key>scale</key>
<array>

View File

@ -598,7 +598,6 @@ with the same filename but different name
<!-- FS:Beq: Poser icons -->
<texture name="Poser_Visual_On" file_name="icons/visual_pose_enabled.png" />
<texture name="Poser_Visual_Off" file_name="icons/visual_pose_disabled.png" />
<!-- FS:Ansariel: Icon for script errors in V1 status bar -->

View File

@ -59,20 +59,17 @@
</combo_box>
<search_editor label="Regionun adı" name="location" tool_tip="Regionun adını daxil edin"/>
<button label="Axtarış" name="DoSearch" tool_tip="Regioni axtarın"/>
<button label="Təmizlə" name="Clear" tool_tip="İzləməni təmizləyin və xəritəni standart görüntüyə qaytarın"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Məkan:
</text>
<button label="Teleport" name="Teleport" tool_tip="Seçilmiş yere teleportasiya edin"/>
<button label="Kopyala" name="copy_slurl" tool_tip="İnternetdə istifadə üçün SL URL ünvanı ilə cari yerin nümunəsini kopyalayın."/>
<button label="Təmizlə" name="Clear" tool_tip="İzləməni təmizləyin və xəritəni standart görüntüyə qaytarın"/>
<button label="Məkanı göstərin" name="Show Destination" tool_tip="Xəritəni seçilmiş yerə mərkəzləşdirin"/>
<button label="Regionu izləyin" name="track_region" tool_tip="Regioni izləməyə əlavə edin"/>
</panel>
<panel name="layout_panel_5">
<text name="zoom_label">
Yaxınlaşdırma
</text>
</panel>
</layout_panel>
</layout_stack>
</floater>

View File

@ -255,13 +255,6 @@ Susmaya görə dəyərə qayıtmaq üçün UUID yanındakı 'D' düyməsini bas
<button name="Def_UISndSnapshot" tool_tip="Susmaya görə olan UUID-yə sıfırla."/>
<check_box label="Səsin söndürülməsi" name="QuietSnapshotsToDiskCheckBox"/>
<text tool_tip="Teleportasiya zamanı UUID səsi" name="textFSTeleportOut">
Teleportasiya:
</text>
<button name="Prev_UISndTeleportOut" tool_tip="Bu səsi oxut."/>
<button name="Def_UISndTeleportOut" tool_tip="Susmaya görə olan UUID-yə sıfırla."/>
<check_box label="Səsi yandır" name="PlayModeUISndTeleportOut"/>
</panel>
<panel label="İnteerfeys 2" name="UI Sounds tab 2">
<text name="textFSExplanation_tab2">
@ -269,6 +262,13 @@ Susmaya görə dəyərə qayıtmaq üçün UUID yanındakı 'D' düyməsini bas
Susmaya görə dəyərə qayıtmaq üçün UUID yanındakı 'D' düyməsini basın.
</text>
<text tool_tip="Teleportasiya zamanı UUID səsi" name="textFSTeleportOut">
Teleportasiya:
</text>
<button name="Prev_UISndTeleportOut" tool_tip="Bu səsi oxut."/>
<button name="Def_UISndTeleportOut" tool_tip="Susmaya görə olan UUID-yə sıfırla."/>
<check_box label="Səsi yandır" name="PlayModeUISndTeleportOut"/>
<text tool_tip="Dairəvi menyu açılan zaman UUID səsi (Pie Menu)." name="textFSPieMenuAppear">
Dairəvi menyu açılır:
</text>
@ -388,13 +388,6 @@ Susmaya görə dəyərə qayıtmaq üçün UUID yanındakı 'D' düyməsini bas
<button name="Def_UISndFriendshipOffer" tool_tip="Susmaya görə olan UUID-yə sıfırla."/>
<check_box label="Səsi yandır" name="PlayModeUISndFriendshipOffer"/>
<text tool_tip="Teleport təklifi zamanı səsləndirilən UUID səsi." name="textFSTeleportOffer">
Teleport təklifi:
</text>
<button name="Prev_UISndTeleportOffer" tool_tip="Bu səsi oxut."/>
<button name="Def_UISndTeleportOffer" tool_tip="Susmaya görə olan UUID-yə sıfırla."/>
<check_box label="Səsi yandır" name="PlayModeUISndTeleportOffer"/>
</panel>
<panel label="İnteerfeys 3" name="UI Sounds tab 3">
<text name="textFSExplanation_tab3">
@ -402,6 +395,13 @@ Susmaya görə dəyərə qayıtmaq üçün UUID yanındakı 'D' düyməsini bas
Susmaya görə dəyərə qayıtmaq üçün UUID yanındakı 'D' düyməsini basın.
</text>
<text tool_tip="Teleport təklifi zamanı səsləndirilən UUID səsi." name="textFSTeleportOffer">
Teleport təklifi:
</text>
<button name="Prev_UISndTeleportOffer" tool_tip="Bu səsi oxut."/>
<button name="Def_UISndTeleportOffer" tool_tip="Susmaya görə olan UUID-yə sıfırla."/>
<check_box label="Səsi yandır" name="PlayModeUISndTeleportOffer"/>
<text tool_tip="Avadanlıq siyahısı təklif olunan zamanı səsləndirilən UUID səsi." name="textFSInventoryOffer">
Avadanlıq siyahısı təklifi:
</text>

View File

@ -59,6 +59,8 @@
</combo_box>
<search_editor label="Regioner efter navn" name="location" tool_tip="Indtast navn på en region"/>
<button label="Find" name="DoSearch" tool_tip="Led efter region"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Lokation:
</text>

View File

@ -37,4 +37,7 @@
<button label="Fokussieren" name="look_at_btn" />
<button label="Stop" name="stop_btn"/>
<button label="Blacklist" name="bl_btn"/>
<button label="Getragene Av. Sounds blocken" name="block_avatar_worn_sounds_btn" />
<button label="Gerezzte Av. Sounds blocken" name="block_avatar_rezzed_sounds_btn" />
<button label="Av. Gesten-Sounds blocken" name="block_avatar_gesture_sounds_btn" />
</floater>

View File

@ -496,6 +496,8 @@ Nur große Parzellen können in der Suche aufgeführt werden.
<name_list name="AccessList" tool_tip="([LISTED] aufgeführt, [MAX] max)"/>
<button label="Hinzufügen" name="add_allowed"/>
<button label="Entfernen" label_selected="Entfernen" name="remove_allowed"/>
<button label="Exportieren" label_selected="Exportieren" name="export_allowed"/>
<button label="Importieren" label_selected="Importieren" name="import_allowed" tool_tip="Importiert eine CSV-Datei mit ausschließlich gültigen UUIDs - eine pro Zeile ohne extra Zeichen oder Formatierung"/>
</panel>
<panel name="Banned_layout_panel">
<text label="Verbannen" name="BanCheck">
@ -507,6 +509,8 @@ Nur große Parzellen können in der Suche aufgeführt werden.
</name_list>
<button label="Hinzufügen" name="add_banned"/>
<button label="Entfernen" label_selected="Entfernen" name="remove_banned"/>
<button label="Exportieren" label_selected="Exportieren" name="export_banned"/>
<button label="Importieren" label_selected="Importieren" name="import_banned" tool_tip="Importiert eine CSV-Datei mit ausschließlich gültigen UUIDs - eine pro Zeile ohne extra Zeichen oder Formatierung"/>
</panel>
</panel>
<panel label="Erlebnis" name="land_experiences_panel"/>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="Avatar Welcome Pack" title="Avatar-Willkommenspaket"/>

View File

@ -96,8 +96,9 @@
<check_box name="exclude_reflection_probes" label="Reflexionstests"/>
<check_box name="exclude_childprim" label="Kind-Primitive"/>
<check_box name="exclude_neighbor_region" label="Nachbarregionen"/>
<button name="apply" label="Anwenden"/>
</panel>
<button name="apply" label="Anwenden"/>
<button name="save_as_default" label="Als Standard speichern"/>
</panel>
<panel label="Optionen" name="area_search_options_panel">
<text name="display_column">
Spalten anzeigen:

Some files were not shown because too many files have changed in this diff Show More