summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Lihatskiy <118752495+marchcat@users.noreply.github.com>2026-04-16 22:09:14 +0300
committerGitHub <noreply@github.com>2026-04-16 22:09:14 +0300
commit65b9b2cb5cde2c344da51a7b677c1b99591d8ad3 (patch)
tree569f248515a4da0c5643420272ccc5074cb60e45
parentf209affdfdf271098843ba400d7a75b00f827233 (diff)
parent4708693c577eb4ebbae914937fba2ebdc2c31a33 (diff)
Merge pull request #5659 from secondlife/marchcat/slua-26.1.1
Update SLua PV to 26.1.1
-rw-r--r--.github/workflows/build.yaml70
-rw-r--r--.github/workflows/tag-release.yaml36
-rw-r--r--autobuild.xml214
-rw-r--r--doc/BUILD.LINUX.md10
-rw-r--r--indra/cmake/Boost.cmake28
-rw-r--r--indra/cmake/CMakeLists.txt1
-rw-r--r--indra/cmake/Python.cmake67
-rw-r--r--indra/cmake/Velopack.cmake68
-rw-r--r--indra/lib/python/indra/util/llmanifest.py3
-rw-r--r--indra/llcommon/llapp.cpp1
-rw-r--r--indra/llcommon/llapp.h2
-rw-r--r--indra/llcommon/lldate.cpp7
-rw-r--r--indra/llcommon/llerror.cpp6
-rw-r--r--indra/llcommon/llerrorcontrol.h1
-rw-r--r--indra/llcommon/llheteromap.cpp2
-rw-r--r--indra/llcommon/llheteromap.h27
-rw-r--r--indra/llcommon/llinitparam.h129
-rw-r--r--indra/llcommon/llpounceable.h4
-rw-r--r--indra/llcommon/llprocess.cpp5
-rw-r--r--indra/llcommon/llregistry.h26
-rw-r--r--indra/llcommon/llsd.cpp162
-rw-r--r--indra/llcommon/llsd.h39
-rw-r--r--indra/llcommon/llsdjson.cpp4
-rw-r--r--indra/llcommon/llsdserialize.cpp52
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp32
-rw-r--r--indra/llcommon/llsingleton.h4
-rw-r--r--indra/llcommon/llstaticstringtable.h5
-rw-r--r--indra/llcommon/llstl.h39
-rw-r--r--indra/llcommon/lluuid.h19
-rw-r--r--indra/llcommon/workqueue.cpp18
-rw-r--r--indra/llcommon/workqueue.h6
-rw-r--r--indra/llfilesystem/lldiskcache.cpp2
-rw-r--r--indra/llinventory/llinventory.cpp18
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp5
-rw-r--r--indra/llmath/llvolume.cpp31
-rw-r--r--indra/llmeshoptimizer/llmeshoptimizer.cpp1
-rw-r--r--indra/llmessage/llavatarnamecache.cpp18
-rw-r--r--indra/llmessage/llavatarnamecache.h10
-rw-r--r--indra/llmessage/llcachename.cpp15
-rw-r--r--indra/llmessage/llcachename.h3
-rw-r--r--indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp165
-rw-r--r--indra/llphysicsextensionsos/llconvexdecompositionvhacd.h20
-rw-r--r--indra/llprimitive/llgltfmaterial.cpp2
-rw-r--r--indra/llprimitive/llmaterialid.h30
-rw-r--r--indra/llrender/llfontfreetype.h5
-rw-r--r--indra/llrender/llgl.cpp6
-rw-r--r--indra/llrender/llgl.h4
-rw-r--r--indra/llui/llfloater.cpp2
-rw-r--r--indra/llui/llfloaterreg.cpp19
-rw-r--r--indra/llui/llfloaterreg.h13
-rw-r--r--indra/llui/llfolderviewitem.cpp13
-rw-r--r--indra/llui/llfunctorregistry.h5
-rw-r--r--indra/llui/llkeywords.h2
-rw-r--r--indra/llui/llnotifications.cpp7
-rw-r--r--indra/llui/llnotifications.h4
-rw-r--r--indra/llui/llpanel.h4
-rw-r--r--indra/llui/llradiogroup.cpp2
-rw-r--r--indra/llui/llresmgr.cpp40
-rw-r--r--indra/llui/llresmgr.h4
-rw-r--r--indra/llui/llrngwriter.cpp2
-rw-r--r--indra/llui/llscrolllistcolumn.cpp2
-rw-r--r--indra/llui/lltextbase.cpp2
-rw-r--r--indra/llui/lltooltip.cpp2
-rw-r--r--indra/llui/lltrans.h2
-rw-r--r--indra/llui/llui.cpp2
-rw-r--r--indra/llui/llui.h2
-rw-r--r--indra/llui/lluicolortable.cpp9
-rw-r--r--indra/llui/lluicolortable.h4
-rw-r--r--indra/llui/lluictrlfactory.cpp2
-rw-r--r--indra/llui/lluictrlfactory.h12
-rw-r--r--indra/llui/llxuiparser.cpp46
-rw-r--r--indra/llui/llxuiparser.h6
-rw-r--r--indra/llwindow/llkeyboard.h2
-rw-r--r--indra/llwindow/llkeyboardsdl.cpp264
-rw-r--r--indra/llwindow/llkeyboardsdl.h2
-rw-r--r--indra/llwindow/llsdl.cpp2
-rw-r--r--indra/llwindow/llsdl.h2
-rw-r--r--indra/llwindow/llwindowsdl.cpp2
-rw-r--r--indra/llxml/llcontrol.cpp2
-rw-r--r--indra/llxml/llcontrol.h4
-rw-r--r--indra/newview/CMakeLists.txt20
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rw-r--r--indra/newview/app_settings/settings.xml49
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl3
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl9
-rw-r--r--indra/newview/gltf/asset.cpp6
-rw-r--r--indra/newview/gltf/buffer_util.h44
-rw-r--r--indra/newview/gltf/llgltfloader.cpp3
-rw-r--r--indra/newview/installers/windows/installer_template.nsi49
-rw-r--r--indra/newview/llagent.cpp2
-rw-r--r--indra/newview/llappcorehttp.cpp2
-rw-r--r--indra/newview/llappviewer.cpp124
-rw-r--r--indra/newview/llappviewer.h14
-rw-r--r--indra/newview/llappviewerwin32.cpp33
-rw-r--r--indra/newview/llappviewerwin32.h2
-rw-r--r--indra/newview/llavatarlistitem.cpp2
-rw-r--r--indra/newview/llcallingcard.cpp2
-rw-r--r--indra/newview/llcapabilityprovider.h4
-rw-r--r--indra/newview/llfilepicker.cpp3
-rw-r--r--indra/newview/llfilepicker_mac.mm7
-rw-r--r--indra/newview/llfloatermarketplace.cpp1
-rw-r--r--indra/newview/llgltfmateriallist.cpp2
-rw-r--r--indra/newview/llinventorylistitem.cpp2
-rw-r--r--indra/newview/llinventorymodel.cpp70
-rw-r--r--indra/newview/llinventorymodel.h8
-rw-r--r--indra/newview/llinventorypanel.cpp3
-rw-r--r--indra/newview/llinventorypanel.h2
-rw-r--r--indra/newview/lllogininstance.cpp81
-rw-r--r--indra/newview/lllogininstance.h6
-rw-r--r--indra/newview/llmachineid.cpp2
-rw-r--r--indra/newview/llmaterialmgr.h76
-rw-r--r--indra/newview/llmeshrepository.h2
-rw-r--r--indra/newview/llmodelpreview.cpp2
-rw-r--r--indra/newview/llmutelist.cpp4
-rw-r--r--indra/newview/lloutfitgallery.cpp19
-rw-r--r--indra/newview/lloutfitgallery.h2
-rw-r--r--indra/newview/lloutfitslist.cpp17
-rw-r--r--indra/newview/lloutfitslist.h13
-rw-r--r--indra/newview/llpanellogin.cpp16
-rw-r--r--indra/newview/llpanelobjectinventory.cpp2
-rw-r--r--indra/newview/llpanelobjectinventory.h2
-rw-r--r--indra/newview/llperfstats.h2
-rw-r--r--indra/newview/llpreviewscript.cpp28
-rw-r--r--indra/newview/llscriptruntimeperms.h13
-rw-r--r--indra/newview/llselectmgr.cpp9
-rw-r--r--indra/newview/llstartup.cpp89
-rw-r--r--indra/newview/lltexturecache.cpp4
-rw-r--r--indra/newview/lltoastscriptquestion.cpp73
-rw-r--r--indra/newview/llvelopack.cpp1201
-rw-r--r--indra/newview/llvelopack.h59
-rw-r--r--indra/newview/llversioninfo.cpp2
-rw-r--r--indra/newview/llversioninfo.h4
-rw-r--r--indra/newview/llviewercontrol.cpp1
-rw-r--r--indra/newview/llviewermenu.cpp90
-rw-r--r--indra/newview/llviewermessage.cpp24
-rw-r--r--indra/newview/llviewernetwork.cpp8
-rw-r--r--indra/newview/llviewerobject.cpp58
-rw-r--r--indra/newview/llviewerobject.h6
-rw-r--r--indra/newview/llviewerobjectlist.cpp2
-rw-r--r--indra/newview/llviewerobjectlist.h4
-rw-r--r--indra/newview/llviewerprecompiledheaders.h2
-rw-r--r--indra/newview/llviewerregion.cpp29
-rw-r--r--indra/newview/llviewerregion.h8
-rw-r--r--indra/newview/llviewerstats.cpp6
-rw-r--r--indra/newview/llviewertexture.cpp40
-rw-r--r--indra/newview/llviewerwindow.cpp6
-rw-r--r--indra/newview/llviewerwindow.h6
-rw-r--r--indra/newview/llvoicewebrtc.cpp31
-rw-r--r--indra/newview/llvvmquery.cpp189
-rw-r--r--indra/newview/llvvmquery.h42
-rw-r--r--indra/newview/llwearableitemslist.cpp10
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml12
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml28
-rw-r--r--indra/newview/skins/default/xui/en/panel_notification.xml8
-rw-r--r--indra/newview/skins/default/xui/en/panel_script_question_toast.xml6
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml3
-rw-r--r--indra/newview/tests/lldateutil_test.cpp6
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp2
-rwxr-xr-xindra/newview/viewer_manifest.py261
-rw-r--r--indra/viewer_components/login/lllogin.cpp62
160 files changed, 3797 insertions, 1259 deletions
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 01071d1377..5b6e30a2a3 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -2,6 +2,14 @@ name: Build
on:
workflow_dispatch:
+ inputs:
+ installer_type:
+ description: 'Windows installer type'
+ type: choice
+ options:
+ - velopack
+ - nsis
+ default: 'velopack'
pull_request:
push:
branches: ["main", "release/*", "project/*"]
@@ -54,6 +62,20 @@ jobs:
relnotes: ${{ steps.which-branch.outputs.relnotes }}
imagename: ${{ steps.build.outputs.imagename }}
configuration: ${{ matrix.configuration }}
+ # Windows Velopack outputs (passed to sign-pkg-windows)
+ velopack_pack_id: ${{ steps.build.outputs.velopack_pack_id }}
+ velopack_pack_version: ${{ steps.build.outputs.velopack_pack_version }}
+ velopack_pack_title: ${{ steps.build.outputs.velopack_pack_title }}
+ velopack_main_exe: ${{ steps.build.outputs.velopack_main_exe }}
+ velopack_exclude: ${{ steps.build.outputs.velopack_exclude }}
+ velopack_icon: ${{ steps.build.outputs.velopack_icon }}
+ velopack_installer_base: ${{ steps.build.outputs.velopack_installer_base }}
+ # macOS Velopack outputs (passed to sign-pkg-mac)
+ velopack_mac_pack_id: ${{ steps.build.outputs.velopack_mac_pack_id }}
+ velopack_mac_pack_version: ${{ steps.build.outputs.velopack_mac_pack_version }}
+ velopack_mac_pack_title: ${{ steps.build.outputs.velopack_mac_pack_title }}
+ velopack_mac_main_exe: ${{ steps.build.outputs.velopack_mac_main_exe }}
+ velopack_mac_bundle_id: ${{ steps.build.outputs.velopack_mac_bundle_id }}
env:
AUTOBUILD_ADDRSIZE: 64
AUTOBUILD_BUILD_ID: ${{ github.run_id }}
@@ -85,6 +107,8 @@ jobs:
# Only set variants to the one configuration: don't let build.sh loop
# over variants, let GitHub distribute variants over multiple hosts.
variants: ${{ matrix.configuration }}
+ # Pass USE_VELOPACK to CMake when using Velopack installer (default) - Windows and macOS
+ autobuild_configure_parameters: ${{ (contains(matrix.runner, 'windows') || contains(matrix.runner, 'macos')) && (github.event.inputs.installer_type || 'velopack') == 'velopack' && '-- -DUSE_VELOPACK:BOOL=ON' || '' }}
steps:
- name: Checkout code
uses: actions/checkout@v6
@@ -157,6 +181,17 @@ jobs:
with:
token: ${{ github.token }}
+ - name: Setup .NET for Velopack
+ if: (runner.os == 'Windows' || runner.os == 'macOS') && (github.event.inputs.installer_type || 'velopack') == 'velopack'
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '9.0.x'
+
+ - name: Install Velopack CLI
+ if: (runner.os == 'Windows' || runner.os == 'macOS') && (github.event.inputs.installer_type || 'velopack') == 'velopack'
+ shell: bash
+ run: dotnet tool install -g vpk
+
- name: Build
id: build
shell: bash
@@ -295,7 +330,7 @@ jobs:
echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT
- name: Upload executable
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer' && steps.build.outputs.viewer_app
with:
name: "${{ steps.build.outputs.artifact }}-app"
@@ -305,14 +340,14 @@ jobs:
# The other upload of nontrivial size is the symbol file. Use a distinct
# artifact for that too.
- name: Upload symbol file
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer' && steps.build.outputs.symbolfile
with:
name: "${{ steps.build.outputs.artifact }}-symbols"
path: ${{ steps.build.outputs.symbolfile }}
- name: Upload metadata
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer'
with:
name: "${{ steps.build.outputs.artifact }}-metadata"
@@ -321,7 +356,7 @@ jobs:
${{ steps.build.outputs.metadata }}
- name: Upload physics package
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
# should only be set for viewer-private
if: matrix.build_variant == 'Viewer' && matrix.configuration == 'Release' && steps.build.outputs.physicstpv
with:
@@ -331,7 +366,7 @@ jobs:
${{ steps.build.outputs.physicstpv }}
- name: Upload appearance utility package
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: matrix.build_variant == 'Viewer' && steps.build.outputs.appearanceutility
with:
name: "${{ steps.build.outputs.artifact }}-appearanceutility"
@@ -352,13 +387,21 @@ jobs:
steps:
- name: Sign and package Windows viewer
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
- uses: secondlife/viewer-build-util/sign-pkg-windows@v2.0.4
+ uses: secondlife/viewer-build-util/sign-pkg-windows@v2.1.0
with:
vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
cert_name: "${{ env.AZURE_CERT_NAME }}"
client_id: "${{ env.AZURE_CLIENT_ID }}"
client_secret: "${{ env.AZURE_CLIENT_SECRET }}"
tenant_id: "${{ env.AZURE_TENANT_ID }}"
+ installer_type: "${{ github.event.inputs.installer_type || 'velopack' }}"
+ velopack_pack_id: "${{ needs.build.outputs.velopack_pack_id }}"
+ velopack_pack_version: "${{ needs.build.outputs.velopack_pack_version }}"
+ velopack_pack_title: "${{ needs.build.outputs.velopack_pack_title }}"
+ velopack_main_exe: "${{ needs.build.outputs.velopack_main_exe }}"
+ velopack_exclude: "${{ needs.build.outputs.velopack_exclude }}"
+ velopack_icon: "${{ needs.build.outputs.velopack_icon }}"
+ velopack_installer_base: "${{ needs.build.outputs.velopack_installer_base }}"
sign-and-package-mac:
env:
@@ -391,7 +434,7 @@ jobs:
- name: Sign and package Mac viewer
if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team
- uses: secondlife/viewer-build-util/sign-pkg-mac@v2
+ uses: secondlife/viewer-build-util/sign-pkg-mac@v2.1.0
with:
channel: ${{ needs.build.outputs.viewer_channel }}
imagename: ${{ needs.build.outputs.imagename }}
@@ -401,6 +444,11 @@ jobs:
note_user: ${{ steps.note-creds.outputs.note_user }}
note_pass: ${{ steps.note-creds.outputs.note_pass }}
note_team: ${{ steps.note-creds.outputs.note_team }}
+ velopack_pack_id: "${{ needs.build.outputs.velopack_mac_pack_id }}"
+ velopack_pack_version: "${{ needs.build.outputs.velopack_mac_pack_version }}"
+ velopack_pack_title: "${{ needs.build.outputs.velopack_mac_pack_title }}"
+ velopack_main_exe: "${{ needs.build.outputs.velopack_mac_main_exe }}"
+ velopack_bundle_id: "${{ needs.build.outputs.velopack_mac_bundle_id }}"
post-windows-symbols:
env:
@@ -485,6 +533,10 @@ jobs:
with:
name: "Linux-app"
+ - uses: actions/download-artifact@v7
+ with:
+ pattern: "*-releases"
+
- name: Rename metadata
run: |
cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml
@@ -512,13 +564,15 @@ jobs:
generate_release_notes: true
target_commitish: ${{ github.sha }}
append_body: true
- fail_on_unmatched_files: true
+ fail_on_unmatched_files: false
files: |
macOS-installer/*.dmg
Windows-installer/*.exe
*.tar.xz
*-autobuild-package.xml
*-viewer_version.txt
+ Windows-releases/*
+ macOS-releases/*
- name: post release URL
run: |
diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml
index 2922065f99..0f826222a0 100644
--- a/.github/workflows/tag-release.yaml
+++ b/.github/workflows/tag-release.yaml
@@ -21,7 +21,9 @@ on:
project:
description: "Project Name (used for channel name in project builds, and tag name for all builds)"
default: "hippo"
- # TODO - add an input for selecting another sha to build other than head of branch
+ tag_override:
+ description: "Override the tag name (optional). If the tag already exists, a numeric suffix is appended."
+ required: false
jobs:
tag-release:
@@ -34,7 +36,7 @@ jobs:
NIGHTLY_DATE=$(date --rfc-3339=date)
echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV}
echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" >> ${GITHUB_ENV}
- - name: Update Tag
+ - name: Create Tag
uses: actions/github-script@v8
with:
# use a real access token instead of GITHUB_TOKEN default.
@@ -44,9 +46,27 @@ jobs:
# this token will need to be renewed anually in January
github-token: ${{ secrets.LL_TAG_RELEASE_TOKEN }}
script: |
- github.rest.git.createRef({
- owner: context.repo.owner,
- repo: context.repo.repo,
- ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}",
- sha: context.sha
- })
+ const override = `${{ inputs.tag_override }}`.trim();
+ const baseTag = override || `${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}`;
+
+ // Try the base tag first, then append -2, -3, etc. if it already exists
+ let tag = baseTag;
+ for (let attempt = 1; ; attempt++) {
+ try {
+ await github.rest.git.createRef({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ ref: `refs/tags/${tag}`,
+ sha: context.sha
+ });
+ core.info(`Created tag: ${tag}`);
+ break;
+ } catch (e) {
+ if (e.status === 422 && attempt < 10) {
+ core.info(`Tag '${tag}' already exists, trying next suffix...`);
+ tag = `${baseTag}-${attempt + 1}`;
+ } else {
+ throw e;
+ }
+ }
+ }
diff --git a/autobuild.xml b/autobuild.xml
index 8f4e540588..feca45d6d8 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -138,11 +138,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>a4553df5b8fde2e9cd54ebb94c6efb8eb5fe3c38</string>
+ <string>61cc299413a32350175cf7139f64388d3d096ec7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-darwin64-13246092114.tar.zst</string>
+ <string>https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-darwin64-20977261894.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -152,11 +152,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>4a2a19dc5cb555e157ad894ba917f5a83a35b20d</string>
+ <string>6b93e323284bfab8ec20a7f3bc740c6915980bf8</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-linux64-13246092114.tar.zst</string>
+ <string>https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-linux64-20977261894.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -166,11 +166,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>8a1fa9366bfe49009286e4805d7aaedb7c3df82e</string>
+ <string>c543437ca30a63dcd2538fffa89a43ef43f625fb</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-boost/releases/download/v1.86.0-be1a669/boost-1.86-windows64-13246092114.tar.zst</string>
+ <string>https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-windows64-20977261894.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -183,7 +183,7 @@
<key>copyright</key>
<string>(see individual source files)</string>
<key>version</key>
- <string>1.86</string>
+ <string>1.90.0-c7a9feb</string>
<key>name</key>
<string>boost</string>
<key>description</key>
@@ -244,11 +244,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>bf2fe4e8272e990bc8687b3b37bf4bb2b2ad6eb4</string>
+ <string>9710f82a237b95aaafbbcf708b89f6015b80d85f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-darwin64-13259816660.tar.zst</string>
+ <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-darwin64-20980076767.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -258,11 +258,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>118e509ca464182ef4b94ee8c4aa5b14a6c52a94</string>
+ <string>6a1725b1bc13634eb4dd872a4f83c3f16497475f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-linux64-13259816660.tar.zst</string>
+ <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-linux64-20980076767.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -272,11 +272,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>d7aee1b2ec17bd88a2c27359281b58a11ec52d48</string>
+ <string>ba9eeb62ae3046d91f9e061db823c1863623b017</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r10/colladadom-2.3.0-r10-windows64-13259816660.tar.zst</string>
+ <string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-windows64-20980076767.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -289,7 +289,7 @@
<key>copyright</key>
<string>Copyright 2006 Sony Computer Entertainment Inc.</string>
<key>version</key>
- <string>2.3.0-r10</string>
+ <string>2.3.0-r11</string>
<key>name</key>
<string>colladadom</string>
</map>
@@ -360,11 +360,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>e742b1e2d0a58d607b023bf55411041ac65e8a76</string>
+ <string>5eab8167cec442e8c156bb653012d7544cca6037</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-darwin64-13259824618.tar.zst</string>
+ <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-darwin64-20982000504.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -374,11 +374,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>49621c70f385d37c95bcb69a9a24d86ac25f4781</string>
+ <string>3465bbe70cfba2814b1fd52094c62804f4067490</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-linux64-13259824618.tar.zst</string>
+ <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-linux64-20982000504.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -388,11 +388,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>2522201692116cf0adb7203e169be9126885108c</string>
+ <string>0e64e20945eeb19259abf8e78400eb492e31eda7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r3/curl-7.54.1-13259824618-windows64-13259824618.tar.zst</string>
+ <string>https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-windows64-20982000504.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -405,7 +405,7 @@
<key>copyright</key>
<string>Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se).</string>
<key>version</key>
- <string>7.54.1-13259824618</string>
+ <string>7.54.1-20982000504</string>
<key>name</key>
<string>curl</string>
<key>description</key>
@@ -606,11 +606,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>5e6c7b9aaf73d90d7feab846a4024193c48eff6c</string>
+ <string>550a90bca35bdbbd615afb1a1c02383cb3b6edbe</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-darwin64-13259804885.tar.zst</string>
+ <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-darwin64-20935810762.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -620,11 +620,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>a9a3c371958e64a49b07d7be8f59218dfd6b0352</string>
+ <string>f52b05392962cb6a8e5f534d8687faa525d4960a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-linux64-13259804885.tar.zst</string>
+ <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-linux64-20935810762.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -634,11 +634,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>ad7fbc4a01607ec43d86035a49dadd43d6f2a4e5</string>
+ <string>3c30052adcbfec572562bb1e7927d7a8f4d93f3d</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r3/freetype-2.13.3-r3-windows64-13259804885.tar.zst</string>
+ <string>https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-windows64-20935810762.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -651,7 +651,7 @@
<key>copyright</key>
<string>Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.</string>
<key>version</key>
- <string>2.13.3-r3</string>
+ <string>2.13.3-r4</string>
<key>name</key>
<string>freetype</string>
<key>description</key>
@@ -1098,11 +1098,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>a453355ee032f79aea4142218a957085a22c7656</string>
+ <string>6fa10d5f44601dda6efc3eda1a9dab22525e7a9a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-darwin64-13246065198.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-darwin64-20934739343.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1112,11 +1112,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>75c7608646c9f5b99b1a9e3946326e2804a304d7</string>
+ <string>112b7f46f5923e6418dfa4bc13ebe2db6911c9b9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-linux64-13246065198.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-linux64-20934739343.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1126,11 +1126,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>09af51774c4ee7c03fe67a87dfc52e846aa625ea</string>
+ <string>2731c45f1e62e33b8612b3ee2b9c4cb39dafbfe2</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.44-r2/libpng-1.6.44-r2-windows64-13246065198.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-windows64-20934739343.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1143,7 +1143,7 @@
<key>copyright</key>
<string>Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson</string>
<key>version</key>
- <string>1.6.44-r2</string>
+ <string>1.6.53-eea12b7</string>
<key>name</key>
<string>libpng</string>
<key>description</key>
@@ -1158,11 +1158,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>372c92936d940b1cfb5ba34310691d4bb435c161</string>
+ <string>c1ad7ff9ec91049c93d2dcd832f81a00f8f4b4b9</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-darwin64-13246071272.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-darwin64-20936141417.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1172,11 +1172,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>ba6fbc34112b1acab1c8615dcd13de983f3678d3</string>
+ <string>7fc2df91648661468a82754b26fd7dedfbef1d39</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-linux64-13246071272.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-linux64-20936141417.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1186,11 +1186,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>71968c4b621636e8ae0c5680e631f4aa67561944</string>
+ <string>84828c26b67c33f0d3e565718943aa339582b34f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.5-r2/libxml2-2.13.5-r2-windows64-13246071272.tar.zst</string>
+ <string>https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-windows64-20936141417.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1203,7 +1203,7 @@
<key>copyright</key>
<string>Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.</string>
<key>version</key>
- <string>2.13.5-r2</string>
+ <string>2.13.9-d53cd6f</string>
<key>name</key>
<string>libxml2</string>
<key>description</key>
@@ -1377,11 +1377,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>874a7d2bc843554aa4facd03b3a6d681f2b5150c</string>
+ <string>3692af717636da9c2b1e0f13eb084ce022b67f6c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-darwin64-11968851109.tar.zst</string>
+ <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-darwin64-20867041007.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1391,11 +1391,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>31a537f1a3d38ef85443214315111dd56a534d9a</string>
+ <string>22ad1be39a1196a1ca3902ba936460cb69252b9c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-linux64-11968851109.tar.zst</string>
+ <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-linux64-20867041007.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1405,11 +1405,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>6fd727a9ccb3e7a6c6b4ffef8179e266c032eb3e</string>
+ <string>2c9769f31da5de3920d7ee400d280398c911a30f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v220-r1/meshoptimizer-220.0.0-r1-windows64-11968851109.tar.zst</string>
+ <string>https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-windows64-20867041007.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1501,11 +1501,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>b628d088e1f368a0cd51a6b66292aaf9a025e2d4</string>
+ <string>85179317015c5c91986000d69c9f61a01af7617f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-darwin64-13246046977.tar.zst</string>
+ <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-darwin64-20933148061.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1515,11 +1515,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>492ce9175b730d43df63821c4481685e035af623</string>
+ <string>ef1524f507f44fed6f1c1f00ae274ddb8a1ac359</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-linux64-13246046977.tar.zst</string>
+ <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-linux64-20933148061.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1529,11 +1529,11 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>58773e707ff3490822b7b8217d7729ade2186632</string>
+ <string>90be39cf789b596377458f1ea78f415a9c281a8c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r3/minizip_ng-4.0.7-r3-windows64-13246046977.tar.zst</string>
+ <string>https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-windows64-20933148061.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1546,7 +1546,7 @@
<key>copyright</key>
<string>This project uses the zlib license. Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler</string>
<key>version</key>
- <string>4.0.7-r3</string>
+ <string>4.0.7-r4</string>
<key>name</key>
<string>minizip-ng</string>
<key>canonical_repo</key>
@@ -1926,11 +1926,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>157193699127ac5056c5fc1a410f9c98d39731e2</string>
+ <string>e08f640fb423f878c288426c836189b30b0c8ad0</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-darwin64-13246054022.tar.zst</string>
+ <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-darwin64-20981673556.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -1940,11 +1940,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>2e29c127dbd002d64ae55bc000f8b6ed0249fad7</string>
+ <string>d83a1e910762b792c90550ce2b8f51f9aaec7570</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-linux64-13246054022.tar.zst</string>
+ <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-linux64-20981673556.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -1954,11 +1954,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>ae9ced89051e03a99628c99b9ac78530fdea1e5a</string>
+ <string>eec78c22e2d1eecf375aa0c6eff08fe67d2316f4</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r3/openssl-1.1.1w-r3-windows64-13246054022.tar.zst</string>
+ <string>https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-windows64-20981673556.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -1971,7 +1971,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>copyright</key>
<string>Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved; Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)</string>
<key>version</key>
- <string>1.1.1w-r3</string>
+ <string>1.1.1w-r4</string>
<key>name</key>
<string>openssl</string>
<key>description</key>
@@ -2578,11 +2578,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>e363e3b889c52fda7601d7aeaa9832307034651e</string>
+ <string>4906257288c61b14d2e16116fc3139af35d3374f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-darwin64-13183604450.tar.zst</string>
+ <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-darwin64-20930307098.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -2592,11 +2592,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>3cdd52f7fb3691789d50f0b40ed6f5642321ff32</string>
+ <string>2b81a6a4ebd9ae5555d48b52eea7c2d875d68f60</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-linux64-13183604450.tar.zst</string>
+ <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-linux64-20930307098.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -2606,11 +2606,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
- <string>e802a28139328bb2421ad39e13d996d350d8106d</string>
+ <string>e2e0f964ba44fe2e6428e1e7ca262a3f80d92e65</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.3-r1/zlib_ng-2.2.3-dev0.g8aa13e3.d20250206-windows64-13183604450.tar.zst</string>
+ <string>https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-windows64-20930307098.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -2623,7 +2623,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>copyright</key>
<string>Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler</string>
<key>version</key>
- <string>2.2.3-dev0.g8aa13e3.d20250206</string>
+ <string>2.2.5-0d88d03</string>
<key>name</key>
<string>zlib-ng</string>
<key>canonical_repo</key>
@@ -2761,45 +2761,95 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>Voxelized Hierarchical Approximate Convex Decomposition</string>
</map>
- <key>websocketpp</key>
+ <key>velopack</key>
<map>
<key>platforms</key>
<map>
- <key>common</key>
+ <key>windows64</key>
<map>
<key>archive</key>
<map>
+ <key>creds</key>
+ <string>github</string>
<key>hash</key>
- <string>a69aa37bfbcb934974f7af906f6dc6b044692f07</string>
+ <string>91abbc360640b5b2e0a4c001a36ad411a9a42602</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
- <string>https://github.com/secondlife/3p-websocketpp/releases/download/v0.8.2-r2/websocketpp-0.8.2.19586590594-common-19586590594.tar.zst</string>
+ <string>https://api.github.com/repos/secondlife-3p/3p-velopack/releases/assets/380583560</string>
</map>
<key>name</key>
- <string>common</string>
+ <string>windows64</string>
+ </map>
+ <key>darwin64</key>
+ <map>
+ <key>archive</key>
+ <map>
+ <key>creds</key>
+ <string>github</string>
+ <key>hash</key>
+ <string>05563a79bdeb83d66a72ac1e97587dc2a8f64511</string>
+ <key>hash_algorithm</key>
+ <string>sha1</string>
+ <key>url</key>
+ <string>https://api.github.com/repos/secondlife-3p/3p-velopack/releases/assets/380583554</string>
+ </map>
+ <key>name</key>
+ <string>darwin64</string>
</map>
</map>
<key>license</key>
- <string>websocketpp</string>
+ <string>MIT</string>
<key>license_file</key>
- <string>LICENSES/websocketpp.txt</string>
+ <string>LICENSES/velopack.txt</string>
<key>copyright</key>
- <string>Copyright (c) 2014, Peter Thorson</string>
+ <string>Velopack Ltd.</string>
<key>version</key>
- <string>0.8.2.19586590594</string>
+ <string>40232ef.23500976684</string>
+ <key>name</key>
+ <string>velopack</string>
+ <key>description</key>
+ <string>Velopack C/C++ Library</string>
+ </map>
+ <key>websocketpp</key>
+ <map>
+ <key>canonical_repo</key>
+ <string>https://github.com/secondlife/3p-websocketpp</string>
+ <key>copyright</key>
+ <string>Copyright (c) 2014, Peter Thorson</string>
+ <key>description</key>
+ <string>WebSocket++ is a C++ header only library for interacting with WebSocket servers and clients.</string>
+ <key>license</key>
+ <string>websocketpp</string>
+ <key>license_file</key>
+ <string>LICENSES/websocketpp.txt</string>
<key>name</key>
<string>websocketpp</string>
+ <key>platforms</key>
+ <map>
+ <key>common</key>
+ <map>
+ <key>archive</key>
+ <map>
+ <key>hash</key>
+ <string>abaea02a43487c07dbeaa2b22a1efcc8b26090d6</string>
+ <key>hash_algorithm</key>
+ <string>sha1</string>
+ <key>url</key>
+ <string>https://github.com/secondlife/3p-websocketpp/releases/download/v0.8.2-r3/websocketpp-0.8.2.24525603568-common-24525603568.tar.zst</string>
+ </map>
+ <key>name</key>
+ <string>common</string>
+ </map>
+ </map>
<key>vcs_branch</key>
<string>refs/tags/v0.8.2</string>
<key>vcs_revision</key>
<string>bdcf1453101976fc4dc26a62c87bc98c12e9c6dc</string>
<key>vcs_url</key>
<string>git://github.com/secondlife/3p-websocketpp.git</string>
- <key>canonical_repo</key>
- <string>https://github.com/secondlife/3p-websocketpp</string>
- <key>description</key>
- <string>WebSocket++ is a C++ header only library for interacting with WebSocket servers and clients.</string>
+ <key>version</key>
+ <string>0.8.2.24525603568</string>
</map>
</map>
<key>package_description</key>
diff --git a/doc/BUILD.LINUX.md b/doc/BUILD.LINUX.md
index 28c0689cd5..09acfafaec 100644
--- a/doc/BUILD.LINUX.md
+++ b/doc/BUILD.LINUX.md
@@ -25,6 +25,11 @@ sudo apt install build-essential cmake git libfontconfig-dev libglib2.0-dev libg
sudo dnf install @development-tools @c-development cmake fontconfig-devel git glib-devel gstreamer1-devel gstreamer1-plugins-base-devel libX11-devel mesa-compat-libOSMesa-devel libglvnd-devel ninja-build python3 vlc-devel wayland-devel
```
+To build with clang instead of gcc, also install:
+```
+sudo dnf install clang lld
+```
+
### OpenSUSE Tumbleweed
```
sudo zypper in -t pattern devel_basis devel_C_C++
@@ -65,7 +70,7 @@ cd ~/code/secondlife/viewer
autobuild configure -c ReleaseOS -A64
```
-### Clang
+### Clang (faster build; less stable)
```
autobuild configure -c ReleaseOS -- -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=LLD
```
@@ -77,3 +82,6 @@ autobuild build -c ReleaseOS --no-configure
> [!NOTE]
> If the above was successful you should find the viewer package in `viewer/build-linux-x86_64/newview`
+
+### Troubleshooting
+- If you encounter warnings, try adding `-- -DGCC_DISABLE_FATAL_WARNINGS=TRUE` or `-DCLANG_DISABLE_FATAL_WARNINGS=TRUE` to the configure command
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 5967a96f8a..fd3e0eccde 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -19,56 +19,50 @@ set(addrsfx "-x${ADDRESS_SIZE}")
find_library(BOOST_CONTEXT_LIBRARY
NAMES
+ libboost_context
libboost_context-mt
libboost_context-mt${addrsfx}
+ boost_context
boost_context-mt
boost_context-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
find_library(BOOST_FIBER_LIBRARY
NAMES
+ libboost_fiber
libboost_fiber-mt
libboost_fiber-mt${addrsfx}
+ boost_fiber
boost_fiber-mt
boost_fiber-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
find_library(BOOST_FILESYSTEM_LIBRARY
NAMES
+ libboost_filesystem
libboost_filesystem-mt
libboost_filesystem-mt${addrsfx}
+ boost_filesystem
boost_filesystem-mt
boost_filesystem-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
find_library(BOOST_PROGRAMOPTIONS_LIBRARY
NAMES
+ libboost_program_options
libboost_program_options-mt
libboost_program_options-mt${addrsfx}
+ boost_program_options
boost_program_options-mt
boost_program_options-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-find_library(BOOST_REGEX_LIBRARY
- NAMES
- libboost_regex-mt
- libboost_regex-mt${addrsfx}
- boost_regex-mt
- boost_regex-mt${addrsfx}
- PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-
-find_library(BOOST_SYSTEM_LIBRARY
- NAMES
- libboost_system-mt
- libboost_system-mt${addrsfx}
- boost_system-mt
- boost_system-mt${addrsfx}
- PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
-
find_library(BOOST_URL_LIBRARY
NAMES
+ libboost_url
libboost_url-mt
libboost_url-mt${addrsfx}
+ boost_url
boost_url-mt
boost_url-mt${addrsfx}
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
@@ -78,8 +72,6 @@ target_link_libraries(ll::boost INTERFACE
${BOOST_CONTEXT_LIBRARY}
${BOOST_FILESYSTEM_LIBRARY}
${BOOST_PROGRAMOPTIONS_LIBRARY}
- ${BOOST_REGEX_LIBRARY}
- ${BOOST_SYSTEM_LIBRARY}
${BOOST_URL_LIBRARY})
if (LINUX)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 6bbc61feaa..ea55bffb35 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -64,6 +64,7 @@ set(cmake_SOURCE_FILES
UI.cmake
UnixInstall.cmake
Variables.cmake
+ Velopack.cmake
VHACD.cmake
ViewerMiscLibs.cmake
VisualLeakDetector.cmake
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index 39fd21c33f..428f9e3326 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -1,57 +1,18 @@
-# -*- cmake -*-
+# Allow explicit Python path via environment variable
+if(DEFINED ENV{PYTHON})
+ set(Python3_ROOT_DIR "$ENV{PYTHON}")
+endif()
-set(PYTHONINTERP_FOUND)
+# On Windows, prefer registry entries to avoid Cygwin/MSYS Python
+# The registry is searched first by default, which finds native Windows Python
+# installations rather than Cygwin/MSYS Python
+if(WINDOWS)
+ set(Python3_FIND_REGISTRY FIRST CACHE STRING "Python search order")
+endif()
-if (DEFINED ENV{PYTHON})
- # Allow python executable to be explicitly set
- set(python "$ENV{PYTHON}")
- set(PYTHONINTERP_FOUND ON)
-elseif (WINDOWS)
- # On Windows, explicitly avoid Cygwin Python.
+# Find Python 3 interpreter
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
- # if the user has their own version of Python installed, prefer that
- foreach(hive HKEY_CURRENT_USER HKEY_LOCAL_MACHINE)
- # prefer more recent Python versions to older ones, if multiple versions
- # are installed
- foreach(pyver 3.14 3.13 3.12 3.11 3.10 3.9 3.8 3.7)
- list(APPEND regpaths "[${hive}\\SOFTWARE\\Python\\PythonCore\\${pyver}\\InstallPath]")
- endforeach()
- endforeach()
-
- # TODO: This logic has the disadvantage that if you have multiple versions
- # of Python installed, the selected path won't necessarily be the newest -
- # e.g. this GLOB will prefer Python310 to Python311. But since pymaybe is
- # checked AFTER the registry entries, this will only surface as a problem if
- # no installed Python appears in the registry.
- file(GLOB pymaybe
- "$ENV{PROGRAMFILES}/Python*"
-## "$ENV{PROGRAMFILES(X86)}/Python*"
- # The Windows environment variable is in fact as shown above, but CMake
- # disallows querying an environment variable containing parentheses -
- # thanks, Windows. Fudge by just appending " (x86)" to $PROGRAMFILES and
- # hoping for the best.
- "$ENV{PROGRAMFILES} (x86)/Python*"
- "c:/Python*")
-
- find_program(python
- NAMES python3.exe python.exe
- NO_DEFAULT_PATH # added so that cmake does not find cygwin python
- PATHS
- ${regpaths}
- ${pymaybe}
- )
- find_package(Python3 COMPONENTS Interpreter)
-else()
- find_program(python python3)
-
- if (python)
- set(PYTHONINTERP_FOUND ON)
- endif (python)
-endif (DEFINED ENV{PYTHON})
-
-if (NOT python)
- message(FATAL_ERROR "No Python interpreter found")
-endif (NOT python)
-
-set(PYTHON_EXECUTABLE "${python}" CACHE FILEPATH "Python interpreter for builds")
+# Set legacy variable name for compatibility with existing code
+set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}" CACHE FILEPATH "Python interpreter for builds")
mark_as_advanced(PYTHON_EXECUTABLE)
diff --git a/indra/cmake/Velopack.cmake b/indra/cmake/Velopack.cmake
new file mode 100644
index 0000000000..a1dbe2cbe9
--- /dev/null
+++ b/indra/cmake/Velopack.cmake
@@ -0,0 +1,68 @@
+# -*- cmake -*-
+# Velopack installer and update framework integration
+# https://velopack.io/
+
+include_guard()
+
+# USE_VELOPACK controls whether to use Velopack for installer packaging (instead of NSIS/DMG)
+option(USE_VELOPACK "Use Velopack for installer packaging" OFF)
+
+if (WINDOWS)
+ include(Prebuilt)
+ use_prebuilt_binary(velopack)
+
+ add_library(ll::velopack INTERFACE IMPORTED)
+
+ target_include_directories(ll::velopack SYSTEM INTERFACE
+ ${LIBS_PREBUILT_DIR}/include/velopack
+ )
+
+ target_link_libraries(ll::velopack INTERFACE
+ ${ARCH_PREBUILT_DIRS_RELEASE}/velopack_libc.lib
+ )
+
+ # Windows system libraries required by Velopack
+ target_link_libraries(ll::velopack INTERFACE
+ winhttp
+ ole32
+ shell32
+ shlwapi
+ version
+ userenv
+ ws2_32
+ bcrypt
+ ntdll
+ )
+
+ target_compile_definitions(ll::velopack INTERFACE LL_VELOPACK=1)
+
+elseif (DARWIN)
+ include(Prebuilt)
+ use_prebuilt_binary(velopack)
+
+ add_library(ll::velopack INTERFACE IMPORTED)
+
+ target_include_directories(ll::velopack SYSTEM INTERFACE
+ ${LIBS_PREBUILT_DIR}/include/velopack
+ )
+
+ target_link_libraries(ll::velopack INTERFACE
+ ${ARCH_PREBUILT_DIRS_RELEASE}/libvelopack_libc.a
+ )
+
+ # macOS system frameworks required by Velopack (Rust static library dependencies)
+ target_link_libraries(ll::velopack INTERFACE
+ "-framework Foundation"
+ "-framework Security"
+ "-framework SystemConfiguration"
+ "-framework AppKit"
+ "-framework CoreFoundation"
+ "-framework CoreServices"
+ "-framework IOKit"
+ "-liconv"
+ "-lresolv"
+ )
+
+ target_compile_definitions(ll::velopack INTERFACE LL_VELOPACK=1)
+
+endif()
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 1bd65eb57d..0ad0b6b1a9 100644
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -157,7 +157,8 @@ BASE_ARGUMENTS=[
for use by a .bat file.""",
default=None),
dict(name='versionfile',
- description="""The name of a file containing the full version number."""),
+ description="""The name of a file containing the full version number.""",
+ default=None),
]
def usage(arguments, srctree=""):
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index aa84895fb8..02d6da989a 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -87,6 +87,7 @@ bool LLApp::sDisableCrashlogger = false;
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
LLAppErrorHandler LLApp::sErrorHandler = NULL;
+bool gDisconnected = false;
LLApp::LLApp()
{
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 57f5a112d9..ce09c566a9 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -50,6 +50,8 @@ void clear_signals();
#endif
+extern bool gDisconnected;
+
class LL_COMMON_API LLApp
{
public:
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index b4cdf3cbda..7f65c0d715 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -41,6 +41,9 @@
#include "llstring.h"
#include "llfasttimer.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
// should be APR_USEC_PER_SEC, but that relies on INT64_C which
// isn't defined in glib under our build set up for some reason
@@ -64,7 +67,7 @@ std::string LLDate::asString() const
{
std::ostringstream stream;
toStream(stream);
- return stream.str();
+ return std::move(stream).str();
}
//@ brief Converts time in seconds since EPOCH
@@ -180,7 +183,7 @@ bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *se
bool LLDate::fromString(const std::string& iso8601_date)
{
- std::istringstream stream(iso8601_date);
+ boost::iostreams::stream<boost::iostreams::array_source> stream(iso8601_date.data(), iso8601_date.size());
return fromStream(stream);
}
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 5b42c83a14..78101e21af 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -522,7 +522,7 @@ namespace
}
- typedef std::map<std::string, LLError::ELevel> LevelMap;
+ typedef std::unordered_map<std::string, LLError::ELevel> LevelMap;
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> CallSiteVector;
@@ -543,7 +543,7 @@ namespace
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
LevelMap mTagLevelMap;
- std::map<std::string, unsigned int> mUniqueLogMessages;
+ std::unordered_map<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
@@ -1451,7 +1451,7 @@ namespace LLError
{
std::ostringstream message_stream;
- std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
+ auto messageIter = s->mUniqueLogMessages.find(message);
if (messageIter != s->mUniqueLogMessages.end())
{
messageIter->second++;
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index d254fa5407..3c58d1df22 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -70,7 +70,6 @@ namespace LLError
Setting a level means log messages at that level or above.
*/
- LL_COMMON_API void setPrintLocation(bool);
LL_COMMON_API void setDefaultLevel(LLError::ELevel);
LL_COMMON_API ELevel getDefaultLevel();
LL_COMMON_API void setAlwaysFlush(bool flush);
diff --git a/indra/llcommon/llheteromap.cpp b/indra/llcommon/llheteromap.cpp
index 823bea7a3c..03dd7856b6 100644
--- a/indra/llcommon/llheteromap.cpp
+++ b/indra/llcommon/llheteromap.cpp
@@ -27,6 +27,6 @@ LLHeteroMap::~LLHeteroMap()
// pair.second is the std::pair; pair.second.first is the void*;
// pair.second.second points to the deleter function
(pair.second.second)(pair.second.first);
- pair.second.first = NULL;
+ pair.second.first = nullptr;
}
}
diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h
index d8e6fefb17..211dfaae83 100644
--- a/indra/llcommon/llheteromap.h
+++ b/indra/llcommon/llheteromap.h
@@ -12,9 +12,10 @@
#if ! defined(LL_LLHETEROMAP_H)
#define LL_LLHETEROMAP_H
+#include <typeindex>
#include <typeinfo>
#include <utility> // std::pair
-#include <map>
+#include <unordered_map>
/**
* LLHeteroMap addresses an odd requirement. Usually when you want to put
@@ -43,7 +44,7 @@ public:
// Look up map entry by typeid(T). We don't simply use mMap[typeid(T)]
// because that requires default-constructing T on every lookup. For
// some kinds of T, that could be expensive.
- TypeMap::iterator found = mMap.find(&typeid(T));
+ TypeMap::iterator found = mMap.find(typeid(T));
if (found == mMap.end())
{
// Didn't find typeid(T). Create an entry. Because we're storing
@@ -52,8 +53,8 @@ public:
void* ptr = new T();
void (*dlfn)(void*) = &deleter<T>;
std::pair<TypeMap::iterator, bool> inserted =
- mMap.insert(TypeMap::value_type(&typeid(T),
- TypeMap::mapped_type(ptr, dlfn)));
+ mMap.emplace(typeid(T),
+ TypeMap::mapped_type(ptr, dlfn));
// Okay, now that we have an entry, claim we found it.
found = inserted.first;
}
@@ -71,23 +72,9 @@ private:
delete static_cast<T*>(p);
}
- // Comparing two std::type_info* values is tricky, because the standard
- // does not guarantee that there will be only one type_info instance for a
- // given type. In other words, &typeid(A) in one part of the program may
- // not always equal &typeid(A) in some other part. Use special comparator.
- struct type_info_ptr_comp
- {
- bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
- {
- return lhs->before(*rhs);
- }
- };
-
- // What we actually store is a map from std::type_info (permitting lookup
+ // What we actually store is a map from std::type_index (permitting lookup
// by object type) to a void* pointer to the object PLUS its deleter.
- typedef std::map<
- const std::type_info*, std::pair<void*, void (*)(void*)>,
- type_info_ptr_comp>
+ typedef std::unordered_map<std::type_index, std::pair<void*, void (*)(void*)>>
TypeMap;
TypeMap mMap;
};
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index b01ea0bfb1..b220afadfc 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -34,7 +34,6 @@
#include <list>
#include <unordered_map>
#include <boost/function.hpp>
-#include <boost/unordered_map.hpp>
#include "llerror.h"
#include "llstl.h"
@@ -267,7 +266,7 @@ namespace LLInitParam
private:
struct Inaccessable{};
public:
- typedef std::map<std::string, T> value_name_map_t;
+ typedef std::unordered_map<std::string, T> value_name_map_t;
typedef Inaccessable name_t;
typedef TypeValues<T> type_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
@@ -294,7 +293,7 @@ namespace LLInitParam
static std::vector<std::string>* getPossibleValues()
{
- return NULL;
+ return nullptr;
}
void assignNamedValue(const Inaccessable& name)
@@ -310,7 +309,7 @@ namespace LLInitParam
return param_value_t::getValue();
}
- static value_name_map_t* getValueNames() {return NULL;}
+ static value_name_map_t* getValueNames() { return nullptr; }
};
// helper class to implement name value lookups
@@ -321,7 +320,7 @@ namespace LLInitParam
{
typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
public:
- typedef typename std::map<std::string, T> value_name_map_t;
+ typedef typename std::unordered_map<std::string, T> value_name_map_t;
typedef std::string name_t;
typedef self_t type_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
@@ -497,9 +496,9 @@ namespace LLInitParam
typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);
typedef std::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t;
- typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t;
- typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t;
- typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_read_func_t> parser_read_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_write_func_t> parser_write_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_inspect_func_t> parser_inspect_func_map_t;
public:
@@ -514,7 +513,7 @@ namespace LLInitParam
template <typename T> bool readValue(T& param, typename std::enable_if_t<!std::is_enum_v<T>>* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T));
if (found_it != mParserReadFuncs->end())
{
return found_it->second(*this, (void*)&param);
@@ -525,14 +524,14 @@ namespace LLInitParam
template <typename T> bool readValue(T& param, typename std::enable_if_t<std::is_enum_v<T> >* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T));
if (found_it != mParserReadFuncs->end())
{
return found_it->second(*this, (void*)&param);
}
else
{
- found_it = mParserReadFuncs->find(&typeid(S32));
+ found_it = mParserReadFuncs->find(typeid(S32));
if (found_it != mParserReadFuncs->end())
{
S32 int_value;
@@ -546,7 +545,7 @@ namespace LLInitParam
template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
{
- parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
+ parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(typeid(T));
if (found_it != mParserWriteFuncs->end())
{
return found_it->second(*this, (const void*)&param, name_stack);
@@ -557,7 +556,7 @@ namespace LLInitParam
// dispatch inspection to registered inspection functions, for each parameter in a param block
template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values)
{
- parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T));
+ parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(typeid(T));
if (found_it != mParserInspectFuncs->end())
{
found_it->second(name_stack, min_count, max_count, possible_values);
@@ -574,16 +573,16 @@ namespace LLInitParam
protected:
template <typename T>
- void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL)
+ void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = nullptr)
{
- mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func));
- mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func));
+ mParserReadFuncs->emplace(typeid(T), read_func);
+ mParserWriteFuncs->emplace(typeid(T), write_func);
}
template <typename T>
void registerInspectFunc(parser_inspect_func_t inspect_func)
{
- mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func));
+ mParserInspectFuncs->emplace(typeid(T), inspect_func);
}
bool mParseSilently;
@@ -614,7 +613,7 @@ namespace LLInitParam
{
struct UserData
{
- virtual ~UserData() {}
+ virtual ~UserData() = default;
};
typedef bool(*merge_func_t)(Param&, const Param&, bool);
@@ -665,7 +664,7 @@ namespace LLInitParam
void aggregateBlockData(BlockDescriptor& src_block_data);
void addParam(ParamDescriptorPtr param, const char* name);
- typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t;
+ typedef std::unordered_map<std::string, ParamDescriptorPtr, ll::string_hash, std::equal_to<>> param_map_t;
typedef std::vector<ParamDescriptorPtr> param_list_t;
typedef std::list<ParamDescriptorPtr> all_params_list_t;
typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t;
@@ -679,38 +678,26 @@ namespace LLInitParam
class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed
};
- //TODO: implement in terms of owned_ptr
- template<typename T>
+ // TODO: implement in terms of owned_ptr
+ template<typename T>
class LazyValue
- {
- public:
- LazyValue()
- : mPtr(NULL)
- {}
+ {
+ public:
+ LazyValue() = default;
- ~LazyValue()
- {
- delete mPtr;
- }
+ ~LazyValue() { delete mPtr; }
- LazyValue(const T& value)
- {
- mPtr = new T(value);
- }
+ LazyValue(const T& value) { mPtr = new T(value); }
- LazyValue(const LazyValue& other)
- : mPtr(NULL)
- {
- *this = other;
- }
+ LazyValue(const LazyValue& other) : mPtr(nullptr) { *this = other; }
- LazyValue& operator = (const LazyValue& other)
- {
+ LazyValue& operator=(const LazyValue& other)
+ {
if (!other.mPtr)
{
delete mPtr;
- mPtr = NULL;
- }
+ mPtr = nullptr;
+ }
else
{
if (!mPtr)
@@ -721,23 +708,21 @@ namespace LLInitParam
{
*mPtr = *(other.mPtr);
}
- }
- return *this;
}
+ return *this;
+ }
bool operator==(const LazyValue& other) const
{
- if (empty() || other.empty()) return false;
+ if (empty() || other.empty())
+ return false;
return *mPtr == *other.mPtr;
}
- bool empty() const
- {
- return mPtr == NULL;
- }
+ bool empty() const { return mPtr == nullptr; }
- void set(const T& other)
- {
+ void set(const T& other)
+ {
if (!mPtr)
{
mPtr = new T(other);
@@ -748,36 +733,26 @@ namespace LLInitParam
}
}
- const T& get() const
- {
- return *ensureInstance();
- }
+ const T& get() const { return *ensureInstance(); }
- T& get()
- {
- return *ensureInstance();
- }
+ T& get() { return *ensureInstance(); }
- operator const T&() const
- {
- return get();
- }
+ operator const T&() const { return get(); }
- private:
- // lazily allocate an instance of T
- T* ensureInstance() const
+ private:
+ // lazily allocate an instance of T
+ T* ensureInstance() const
+ {
+ if (mPtr == nullptr)
{
- if (mPtr == NULL)
- {
- mPtr = new T();
- }
- return mPtr;
+ mPtr = new T();
}
+ return mPtr;
+ }
- private:
-
- mutable T* mPtr;
- };
+ private:
+ mutable T* mPtr = nullptr;
+ };
// root class of all parameter blocks
@@ -864,7 +839,7 @@ namespace LLInitParam
mParamProvided(false)
{}
- virtual ~BaseBlock() {}
+ virtual ~BaseBlock() = default;
bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
param_handle_t getHandleFromParam(const Param* param) const;
diff --git a/indra/llcommon/llpounceable.h b/indra/llcommon/llpounceable.h
index e86098f20b..20561b0c65 100644
--- a/indra/llcommon/llpounceable.h
+++ b/indra/llcommon/llpounceable.h
@@ -38,9 +38,9 @@
#include "llsingleton.h"
#include <boost/call_traits.hpp>
#include <boost/utility/value_init.hpp>
-#include <boost/unordered_map.hpp>
#include <boost/signals2/signal.hpp>
+#include <unordered_map>
#include <type_traits>
// Forward declare the user template, since we want to be able to point to it
@@ -86,7 +86,7 @@ class LLPounceableQueueSingleton:
// instance will call on the SAME LLPounceableQueueSingleton instance --
// given how class statics work. We must keep a separate queue for each
// LLPounceable instance. Use a hash map for that.
- typedef boost::unordered_map<owner_ptr, signal_t> map_t;
+ typedef std::unordered_map<owner_ptr, signal_t> map_t;
public:
// Disambiguate queues belonging to different LLPounceables.
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 706d539df2..90ce71a6a5 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -657,10 +657,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// case), e.g. by calling operator(), returns a reference to *the same
// instance* of the wrapped type that's stored in our Block subclass.
// That's important! We know 'params' persists throughout this method
- // call; but without that guarantee, we'd have to assume that converting
- // one of its members to std::string might return a different (temp)
- // instance. Capturing the c_str() from a temporary std::string is Bad Bad
- // Bad. But armed with this knowledge, when you see params.cwd().c_str(),
+ // call; but without that guarantee, when you see params.cwd().c_str(),
// grit your teeth and smile and carry on.
if (params.cwd.isProvided())
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index 35335e1213..92f8ae3245 100644
--- a/indra/llcommon/llregistry.h
+++ b/indra/llcommon/llregistry.h
@@ -32,21 +32,11 @@
#include "llsingleton.h"
#include "llstl.h"
-template <typename T>
-struct LLRegistryDefaultComparator
-{
- bool operator()(const T& lhs, const T& rhs) const
- {
- using std::less;
- return less<T>()(lhs, rhs);
- }
-};
-
-template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
+template <typename KEY, typename VALUE>
class LLRegistry
{
public:
- typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
+ typedef LLRegistry<KEY, VALUE> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef const VALUE* ptr_const_value_t;
@@ -54,9 +44,9 @@ public:
class Registrar
{
- friend class LLRegistry<KEY, VALUE, COMPARATOR>;
+ friend class LLRegistry<KEY, VALUE>;
public:
- typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;
+ typedef std::map<KEY, VALUE> registry_map_t;
bool add(ref_const_key_t key, ref_const_value_t value)
{
@@ -234,9 +224,9 @@ private:
Registrar mDefaultRegistrar;
};
-template <typename KEY, typename VALUE, typename DERIVED_TYPE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
+template <typename KEY, typename VALUE, typename DERIVED_TYPE>
class LLRegistrySingleton
- : public LLRegistry<KEY, VALUE, COMPARATOR>,
+ : public LLRegistry<KEY, VALUE>,
public LLSingleton<DERIVED_TYPE>
{
// This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton)
@@ -244,7 +234,7 @@ class LLRegistrySingleton
// LLRegistrySingleton. So each concrete subclass needs
// LLSINGLETON(whatever) -- not this intermediate base class.
public:
- typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
+ typedef LLRegistry<KEY, VALUE> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef VALUE* ptr_value_t;
@@ -309,7 +299,7 @@ public:
};
// convenience functions
- typedef typename LLRegistry<KEY, VALUE, COMPARATOR>::Registrar& ref_registrar_t;
+ typedef typename LLRegistry<KEY, VALUE>::Registrar& ref_registrar_t;
static ref_registrar_t currentRegistrar()
{
return singleton_t::instance().registry_t::currentRegistrar();
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index ea6d6a308a..ad2ce231fa 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -38,6 +38,9 @@
#include <limits>
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
// Defend against a caller forcibly passing a negative number into an unsigned
// size_t index param
inline
@@ -102,6 +105,9 @@ protected:
U32 mUseCount;
public:
+ static void destruct(Impl*& var);
+ ///< safely decrement or destroy var
+
static void reset(Impl*& var, Impl* impl);
///< safely set var to refer to the new impl (possibly shared)
@@ -165,7 +171,7 @@ public:
virtual const LLSD& ref(size_t) const { return undef(); }
virtual LLSD::map_const_iterator beginMap() const { return endMap(); }
- virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); }
+ virtual LLSD::map_const_iterator endMap() const { static const LLSD::llsd_map_t empty; return empty.end(); }
virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); }
@@ -344,18 +350,7 @@ namespace
LLSD::Real ImplString::asReal() const
{
- F64 v = 0.0;
- std::istringstream i_stream(mValue);
- i_stream >> v;
-
- // we would probably like to ignore all trailing whitespace as
- // well, but for now, simply eat the next character, and make
- // sure we reached the end of the string.
- // *NOTE: gcc 2.95 does not generate an eof() event on the
- // stream operation above, so we manually get here to force it
- // across platforms.
- int c = i_stream.get();
- return ((EOF ==c) ? v : 0.0);
+ return llsd::string_to_real(mValue);
}
@@ -430,7 +425,7 @@ namespace
class ImplMap final : public LLSD::Impl
{
private:
- typedef std::map<LLSD::String, LLSD, std::less<>> DataMap;
+ using DataMap = LLSD::llsd_map_t;
DataMap mData;
@@ -456,7 +451,7 @@ namespace
<< it.second.asXMLRPCValue() << "</member>";
}
os << "</struct>";
- return os.str();
+ return std::move(os).str();
}
virtual bool has(std::string_view) const;
@@ -466,8 +461,13 @@ namespace
using LLSD::Impl::ref; // Unhiding ref(size_t)
virtual LLSD get(std::string_view) const;
virtual LLSD getKeys() const;
+ void insert(std::string&& k, const LLSD& v);
+ void insert(std::string&& k, LLSD&& v);
void insert(std::string_view k, const LLSD& v);
+ void insert(std::string_view k, LLSD&& v);
virtual void erase(const LLSD::String&);
+ LLSD& ref(std::string&&);
+ virtual const LLSD& ref(std::string&&) const;
LLSD& ref(std::string_view);
virtual const LLSD& ref(std::string_view) const;
@@ -524,18 +524,58 @@ namespace
return keys;
}
+ void ImplMap::insert(std::string&& k, const LLSD& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(std::move(k), v);
+ }
+
+ void ImplMap::insert(std::string&& k, LLSD&& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(std::move(k), std::move(v));
+ }
+
void ImplMap::insert(std::string_view k, const LLSD& v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.emplace(k, v);
}
+ void ImplMap::insert(std::string_view k, LLSD&& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(k, std::move(v));
+ }
+
void ImplMap::erase(const LLSD::String& k)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.erase(k);
}
+ LLSD& ImplMap::ref(std::string&& k)
+ {
+ DataMap::iterator i = mData.lower_bound(k);
+ if (i == mData.end() || mData.key_comp()(k, i->first))
+ {
+ return mData.emplace_hint(i, std::make_pair(std::move(k), LLSD()))->second;
+ }
+
+ return i->second;
+ }
+
+ const LLSD& ImplMap::ref(std::string&& k) const
+ {
+ DataMap::const_iterator i = mData.lower_bound(k);
+ if (i == mData.end() || mData.key_comp()(k, i->first))
+ {
+ return undef();
+ }
+
+ return i->second;
+ }
+
LLSD& ImplMap::ref(std::string_view k)
{
DataMap::iterator i = mData.lower_bound(k);
@@ -597,7 +637,7 @@ namespace
ImplArray(const DataVector& data) : mData(data) { }
public:
- ImplArray() { }
+ ImplArray() = default;
virtual ImplArray& makeArray(Impl*&);
@@ -614,7 +654,7 @@ namespace
os << it.asXMLRPCValue();
}
os << "</data></array>";
- return os.str();
+ return std::move(os).str();
}
using LLSD::Impl::get; // Unhiding get(LLSD::String)
@@ -624,10 +664,13 @@ namespace
virtual LLSD get(size_t) const;
void set(size_t, const LLSD&);
void insert(size_t, const LLSD&);
+ void insert(size_t, LLSD&&);
LLSD& append(const LLSD&);
+ LLSD& append(LLSD&&);
virtual void erase(size_t);
LLSD& ref(size_t);
virtual const LLSD& ref(size_t) const;
+ void reserve(size_t size) { mData.reserve(size); }
LLSD::array_iterator beginArray() { return mData.begin(); }
LLSD::array_iterator endArray() { return mData.end(); }
@@ -689,12 +732,31 @@ namespace
mData.insert(mData.begin() + index, v);
}
+ void ImplArray::insert(size_t i, LLSD&& v)
+ {
+ NEGATIVE_EXIT(i);
+ DataVector::size_type index = i;
+
+ if (index >= mData.size()) // tbd - sanity check limit for index ?
+ {
+ mData.resize(index + 1);
+ }
+
+ mData.insert(mData.begin() + index, std::move(v));
+ }
+
LLSD& ImplArray::append(const LLSD& v)
{
mData.push_back(v);
return mData.back();
}
+ LLSD& ImplArray::append(LLSD&& v)
+ {
+ mData.push_back(std::move(v));
+ return mData.back();
+ }
+
void ImplArray::erase(size_t i)
{
NEGATIVE_EXIT(i);
@@ -762,6 +824,14 @@ LLSD::Impl::~Impl()
--sOutstandingCount;
}
+void LLSD::Impl::destruct(Impl*& var)
+{
+ if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
+ {
+ delete var;
+ }
+}
+
void LLSD::Impl::reset(Impl*& var, Impl* impl)
{
if (impl && impl->mUseCount != STATIC_USAGE_COUNT)
@@ -960,7 +1030,7 @@ namespace
LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; }
-LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
+LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::destruct(impl); }
LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); }
void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); }
@@ -1036,13 +1106,31 @@ LLSD LLSD::emptyMap()
bool LLSD::has(const std::string_view k) const { return safe(impl).has(k); }
LLSD LLSD::get(const std::string_view k) const { return safe(impl).get(k); }
LLSD LLSD::getKeys() const { return safe(impl).getKeys(); }
+void LLSD::insert(std::string&& k, const LLSD& v) { makeMap(impl).insert(std::move(k), v); }
+void LLSD::insert(std::string&& k, LLSD&& v) { makeMap(impl).insert(std::move(k), std::move(v)); }
void LLSD::insert(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); }
+void LLSD::insert(std::string_view k, LLSD&& v) { makeMap(impl).insert(k, std::move(v)); }
+LLSD& LLSD::with(std::string&& k, const LLSD& v)
+ {
+ makeMap(impl).insert(std::move(k), v);
+ return *this;
+ }
+LLSD& LLSD::with(std::string&& k, LLSD&& v)
+ {
+ makeMap(impl).insert(std::move(k), std::move(v));
+ return *this;
+ }
LLSD& LLSD::with(std::string_view k, const LLSD& v)
{
makeMap(impl).insert(k, v);
return *this;
}
+LLSD& LLSD::with(std::string_view k, LLSD&& v)
+ {
+ makeMap(impl).insert(k, std::move(v));
+ return *this;
+ }
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
LLSD& LLSD::operator[](const std::string_view k)
@@ -1050,6 +1138,13 @@ LLSD& LLSD::operator[](const std::string_view k)
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return makeMap(impl).ref(k);
}
+
+LLSD& LLSD::operator[](std::string&& k)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ return makeMap(impl).ref(std::move(k));
+}
+
const LLSD& LLSD::operator[](const std::string_view k) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
@@ -1063,18 +1158,33 @@ LLSD LLSD::emptyArray()
return v;
}
+LLSD LLSD::emptyReservedArray(size_t size)
+{
+ LLSD v;
+ makeArray(v.impl).reserve(size);
+ return v;
+}
+
size_t LLSD::size() const { return safe(impl).size(); }
LLSD LLSD::get(Integer i) const { return safe(impl).get(i); }
void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); }
+void LLSD::set(Integer i, LLSD&& v) { makeArray(impl).set(i, std::move(v)); }
void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
+void LLSD::insert(Integer i, LLSD&& v) { makeArray(impl).insert(i, std::move(v)); }
LLSD& LLSD::with(Integer i, const LLSD& v)
{
makeArray(impl).insert(i, v);
return *this;
}
+LLSD& LLSD::with(Integer i, LLSD&& v)
+ {
+ makeArray(impl).insert(i, std::move(v));
+ return *this;
+ }
LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); }
+LLSD& LLSD::append(LLSD&& v) { return makeArray(impl).append(std::move(v)); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
LLSD& LLSD::operator[](size_t i)
@@ -1142,6 +1252,22 @@ LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl)
namespace llsd
{
+LLSD::Real string_to_real(std::string_view in_string)
+{
+ LLSD::Real v = 0.0;
+ boost::iostreams::stream<boost::iostreams::array_source> i_stream(in_string.data(), in_string.size());
+ i_stream >> v;
+
+ // we would probably like to ignore all trailing whitespace as
+ // well, but for now, simply eat the next character, and make
+ // sure we reached the end of the string.
+ // *NOTE: gcc 2.95 does not generate an eof() event on the
+ // stream operation above, so we manually get here to force it
+ // across platforms.
+ int c = i_stream.get();
+ return ((EOF == c) ? v : 0.0);
+}
+
U32 allocationCount() { return LLSD::Impl::sAllocationCount; }
U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; }
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index d2b3548831..afe35a65ba 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -34,6 +34,7 @@
#include "stdtypes.h"
#include "lldate.h"
+#include "llstl.h"
#include "lluri.h"
#include "lluuid.h"
@@ -321,11 +322,34 @@ public:
bool has(const std::string_view) const;
LLSD get(const std::string_view) const;
LLSD getKeys() const; // Return an LLSD array with keys as strings
+ void insert(const char* k, const LLSD& v)
+ {
+ return insert(std::string_view(k), v);
+ }
+ void insert(const char* k , LLSD&& v)
+ {
+ return insert(std::string_view(k), std::move(v));
+ }
+ void insert(std::string&&, const LLSD&);
+ void insert(std::string&&, LLSD&&);
void insert(std::string_view, const LLSD&);
+ void insert(std::string_view, LLSD&&);
void erase(const String&);
+ LLSD& with(const char* k, const LLSD& v)
+ {
+ return with(std::string_view(k), v);
+ }
+ LLSD& with(const char* k, LLSD&& v)
+ {
+ return with(std::string_view(k), std::move(v));
+ }
+ LLSD& with(std::string&&, const LLSD&);
+ LLSD& with(std::string&&, LLSD&&);
LLSD& with(std::string_view, const LLSD&);
+ LLSD& with(std::string_view, LLSD&&);
LLSD& operator[](const std::string_view);
+ LLSD& operator[](std::string&&);
LLSD& operator[](const char* c)
{
return c ? (*this)[std::string_view(c)] : *this;
@@ -339,14 +363,22 @@ public:
/** @name Array Values */
//@{
+ // Allocate an empty array
static LLSD emptyArray();
+ // Allocate an array with internal storage reserved but not initialized like a std::vector
+ static LLSD emptyReservedArray(size_t size);
+
LLSD get(Integer) const;
void set(Integer, const LLSD&);
+ void set(Integer, LLSD&&);
void insert(Integer, const LLSD&);
+ void insert(Integer, LLSD&&);
LLSD& append(const LLSD&);
+ LLSD& append(LLSD&&);
void erase(Integer);
LLSD& with(Integer, const LLSD&);
+ LLSD& with(Integer, LLSD&&);
// accept size_t so we can index relative to size()
const LLSD& operator[](size_t) const;
@@ -366,8 +398,9 @@ public:
//@{
size_t size() const;
- typedef std::map<String, LLSD>::iterator map_iterator;
- typedef std::map<String, LLSD>::const_iterator map_const_iterator;
+ using llsd_map_t = std::map<String, LLSD, std::less<>>;
+ typedef llsd_map_t::iterator map_iterator;
+ typedef llsd_map_t::const_iterator map_const_iterator;
map_iterator beginMap();
map_iterator endMap();
@@ -512,6 +545,8 @@ LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
namespace llsd
{
+ // Used by LLSD::ImplString to convert string type to real
+ LLSD::Real string_to_real(std::string_view in_string);
#ifdef LLSD_DEBUG_INFO
/** @name Unit Testing Interface */
diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp
index 9abca48670..acd4bafb85 100644
--- a/indra/llcommon/llsdjson.cpp
+++ b/indra/llcommon/llsdjson.cpp
@@ -64,7 +64,7 @@ LLSD LlsdFromJson(const boost::json::value& val)
const boost::json::array& array = val.as_array();
size_t size = array.size();
// allocate elements 0 .. (size() - 1) to avoid incremental allocation
- if (! array.empty())
+ if (!array.empty())
{
result[size - 1] = LLSD();
}
@@ -78,7 +78,7 @@ LLSD LlsdFromJson(const boost::json::value& val)
result = LLSD::emptyMap();
for (const auto& element : val.as_object())
{
- result[element.key()] = LlsdFromJson(element.value());
+ result[std::string_view(element.key())] = LlsdFromJson(element.value());
}
break;
}
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 3cc960698e..7fe1f9cdd4 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -775,7 +775,8 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c
// There must be a value for every key, thus
// child_count must be greater than 0.
parse_count += count;
- map.insert(name, child);
+ map.insert(std::move(name), std::move(child)); // Move as name will be filled on next iteration
+ name.clear();
}
else
{
@@ -822,7 +823,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept
else
{
parse_count += count;
- array.append(child);
+ array.append(std::move(child));
}
c = get(istr);
}
@@ -841,7 +842,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
auto count = deserialize_string(istr, value, mMaxBytesLeft);
if(PARSE_FAILURE == count) return false;
account(count);
- data = value;
+ data = std::move(value);
return true;
}
@@ -872,10 +873,10 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
if(len)
{
value.resize(len);
- account(fullread(istr, (char *)&value[0], len));
+ account(fullread(istr, (char*)value.data(), len));
}
c = get(istr); // strip off the trailing double-quote
- data = value;
+ data = std::move(value);
}
else if(0 == strncmp("b64", buf, 3))
{
@@ -885,7 +886,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
std::stringstream coded_stream;
get(istr, *(coded_stream.rdbuf()), '\"');
c = get(istr);
- std::string encoded(coded_stream.str());
+ std::string encoded(std::move(coded_stream).str());
S32 len = apr_base64_decode_len(encoded.c_str());
std::vector<U8> value;
if(len)
@@ -894,7 +895,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
len = apr_base64_decode_binary(&value[0], encoded.c_str());
value.resize(len);
}
- data = value;
+ data = std::move(value);
}
else if(0 == strncmp("b16", buf, 3))
{
@@ -925,7 +926,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
// copy the data out of the byte buffer
value.insert(value.end(), byte_buffer, write);
}
- data = value;
+ data = std::move(value);
}
else
{
@@ -1077,7 +1078,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
}
else
{
- data = value;
+ data = std::move(value);
account(cnt);
}
if(istr.fail())
@@ -1094,7 +1095,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
std::string value;
if(parseString(istr, value))
{
- data = value;
+ data = std::move(value);
}
else
{
@@ -1159,7 +1160,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
value.resize(size);
account(fullread(istr, (char*)&value[0], size));
}
- data = value;
+ data = std::move(value);
}
if(istr.fail())
{
@@ -1218,7 +1219,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con
// There must be a value for every key, thus child_count
// must be greater than 0.
parse_count += child_count;
- map.insert(name, child);
+ map.insert(std::move(name), std::move(child));
}
else
{
@@ -1238,13 +1239,12 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con
S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
{
- array = LLSD::emptyArray();
U32 value_nbo = 0;
read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
S32 size = (S32)ntohl(value_nbo);
- // *FIX: This would be a good place to reserve some space in the
- // array...
+ // Preallocate array to avoid incremental allocation
+ array = LLSD::emptyReservedArray(size);
S32 parse_count = 0;
S32 count = 0;
@@ -1260,7 +1260,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth)
if(child_count)
{
parse_count += child_count;
- array.append(child);
+ array.append(std::move(child));
}
++count;
c = istr.peek();
@@ -1279,18 +1279,15 @@ bool LLSDBinaryParser::parseString(
std::istream& istr,
std::string& value) const
{
- // *FIX: This is memory inefficient.
U32 value_nbo = 0;
read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
S32 size = (S32)ntohl(value_nbo);
if(mCheckLimits && (size > mMaxBytesLeft)) return false;
if(size < 0) return false;
- std::vector<char> buf;
if(size)
{
- buf.resize(size);
- account(fullread(istr, &buf[0], size));
- value.assign(buf.begin(), buf.end());
+ value.resize(size);
+ account(fullread(istr, value.data(), size));
}
return true;
}
@@ -1781,7 +1778,7 @@ llssize deserialize_string_delim(
}
}
- value = write_buffer.str();
+ value = std::move(write_buffer).str();
return count;
}
@@ -1802,15 +1799,12 @@ llssize deserialize_string_raw(
{
// We probably have a valid raw string. determine
// the size, and read it.
- // *FIX: This is memory inefficient.
- auto len = strtol(buf + 1, NULL, 0);
+ auto len = strtol(buf + 1, nullptr, 0);
if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE;
- std::vector<char> buf;
if(len)
{
- buf.resize(len);
- count += fullread(istr, (char *)&buf[0], len);
- value.assign(buf.begin(), buf.end());
+ value.resize(len);
+ count += fullread(istr, value.data(), len);
}
c = istr.get();
++count;
@@ -2166,7 +2160,7 @@ std::string zip_llsd(LLSD& data)
return std::string();
}
- std::string source = llsd_strm.str();
+ std::string source = std::move(llsd_strm).str();
U8 out[CHUNK];
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 6396caf8d5..f399c51608 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -31,6 +31,8 @@
#include <deque>
#include "apr_base64.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
#include <boost/regex.hpp>
extern "C"
@@ -645,7 +647,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch
if (mCurrentKey.empty()) { return startSkipping(); }
LLSD& map = *mStack.back();
- LLSD& newElement = map[mCurrentKey];
+ LLSD& newElement = map[std::move(mCurrentKey)];
mStack.push_back(&newElement);
mCurrentKey.clear();
@@ -709,7 +711,8 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
return;
case ELEMENT_KEY:
- mCurrentKey = mCurrentContent;
+ mCurrentKey = std::move(mCurrentContent); // This is safe to move as we are in the end element handler
+ mCurrentContent.clear(); // Ensure mCurrentContent is empty for subsequent use
return;
default:
@@ -742,14 +745,22 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
}
else
{
- value = LLSD(mCurrentContent).asInteger();
+ // This must treat "1.23" not as an error, but as a number, which is
+ // then truncated down to an integer. Hence, this code doesn't call
+ // std::istringstream::operator>>(int&), which would not consume the
+ // ".23" portion.
+
+ // Utilizes implementation used internally by LLSD::ImplString::asInteger
+ value = (int)llsd::string_to_real(mCurrentContent);
}
}
break;
case ELEMENT_REAL:
{
- value = LLSD(mCurrentContent).asReal();
+ // Utilizes implementation used internally by LLSD::ImplString::asReal
+ value = llsd::string_to_real(mCurrentContent);
+
// removed since this breaks when locale has decimal separator that isn't '.'
// investigated changing local to something compatible each time but deemed higher
// risk that just using LLSD.asReal() each time.
@@ -766,19 +777,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
break;
case ELEMENT_STRING:
- value = mCurrentContent;
+ value = std::move(mCurrentContent); // This is safe to move as we are in the end element handler and this is cleared below
break;
case ELEMENT_UUID:
- value = LLSD(mCurrentContent).asUUID();
+ value = LLUUID(mCurrentContent);
break;
case ELEMENT_DATE:
- value = LLSD(mCurrentContent).asDate();
+ value = LLDate(mCurrentContent);
break;
case ELEMENT_URI:
- value = LLSD(mCurrentContent).asURI();
+ value = LLURI(mCurrentContent);
break;
case ELEMENT_BINARY:
@@ -787,15 +798,14 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
// created by python and other non-linden systems - DEV-39358
// Fortunately we have very little binary passing now,
// so performance impact shold be negligible. + poppy 2009-09-04
- boost::regex r;
- r.assign("\\s");
+ static const boost::regex r("\\s");
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
S32 len = apr_base64_decode_len(stripped.c_str());
std::vector<U8> data;
data.resize(len);
len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
- value = data;
+ value = std::move(data);
break;
}
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 81e69ab63c..ebef2489ce 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -25,10 +25,10 @@
#ifndef LLSINGLETON_H
#define LLSINGLETON_H
-#include <boost/unordered_set.hpp>
#include <initializer_list>
#include <list>
#include <typeinfo>
+#include <unordered_set>
#include <vector>
#include <mutex>
#include "lockstatic.h"
@@ -61,7 +61,7 @@ private:
static vec_t dep_sort();
// we directly depend on these other LLSingletons
- typedef boost::unordered_set<LLSingletonBase*> set_t;
+ typedef std::unordered_set<LLSingletonBase*> set_t;
set_t mDepends;
protected:
diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h
index 66ba3487c4..edff955ee7 100644
--- a/indra/llcommon/llstaticstringtable.h
+++ b/indra/llcommon/llstaticstringtable.h
@@ -29,9 +29,10 @@
#define LL_STATIC_STRING_TABLE_H
#include "lldefs.h"
-#include <boost/unordered_map.hpp>
#include "llstl.h"
+#include <unordered_map>
+
class LLStaticHashedString
{
public:
@@ -74,7 +75,7 @@ struct LLStaticStringHasher
template< typename MappedObject >
class LL_COMMON_API LLStaticStringTable
- : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
+ : public std::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
{
};
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 779d822970..bb8055ed46 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -34,6 +34,7 @@
#include <vector>
#include <list>
#include <set>
+#include <typeindex>
#include <typeinfo>
#include <boost/iterator/filter_iterator.hpp>
@@ -230,12 +231,10 @@ void delete_and_clear_array(T*& ptr)
template <typename T>
inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_type const& key)
{
- // Typedef here avoids warnings because of new c++ naming rules.
- typedef typename T::const_iterator map_iter;
- map_iter iter = inmap.find(key);
+ auto iter = inmap.find(key);
if(iter == inmap.end())
{
- return NULL;
+ return nullptr;
}
else
{
@@ -244,8 +243,8 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty
};
// helper function which returns true if key is in inmap.
-template <typename K, typename T>
-inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
+template <typename T>
+inline bool is_in_map(const T& inmap, typename T::key_type const& key)
{
if(inmap.find(key) == inmap.end())
{
@@ -261,12 +260,10 @@ inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
// To replace LLSkipMap getIfThere, use:
// get_if_there(map, key, 0)
// WARNING: Make sure default_value (generally 0) is not a valid map entry!
-template <typename K, typename T>
-inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
+template <typename T>
+inline typename T::mapped_type get_if_there(const T& inmap, typename T::key_type const& key, typename T::mapped_type default_value)
{
- // Typedef here avoids warnings because of new c++ naming rules.
- typedef typename std::map<K,T>::const_iterator map_iter;
- map_iter iter = inmap.find(key);
+ auto iter = inmap.find(key);
if(iter == inmap.end())
{
return default_value;
@@ -904,4 +901,24 @@ namespace LL
} // namespace LL
+// Transparent string hashing helper for use with std::unordered_*
+// std::unordered_map<std::string, val, ll::string_hash, std::equal_to<>>
+namespace ll
+{
+ struct string_hash
+ {
+ using is_transparent = void;
+ [[nodiscard]] size_t operator()(char const* rhs) const { return std::hash<std::string_view>{}(rhs); }
+ [[nodiscard]] size_t operator()(std::string_view rhs) const { return std::hash<std::string_view>{}(rhs); }
+ [[nodiscard]] size_t operator()(const std::string& rhs) const { return std::hash<std::string>{}(rhs); }
+ };
+} // namespace ll
+
+// Specialize ostream for std::type_index to allow log output
+inline std::ostream& operator<<(std::ostream& s, std::type_index type)
+{
+ s << type.name();
+ return s;
+}
+
#endif // LL_LLSTL_H
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index e6b0eea7a1..122cf414ca 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -26,6 +26,7 @@
#ifndef LL_LLUUID_H
#define LL_LLUUID_H
+#include <functional>
#include <iostream>
#include <set>
#include <vector>
@@ -178,15 +179,27 @@ namespace std
{
inline size_t operator()(const LLUUID& id) const noexcept
{
- return (size_t)id.getDigest64();
+ size_t h = 0;
+ // Golden ratio hash with avalanche mixing
+ // Process 8 bytes at a time by manually constructing 64-bit values
+ // Shift by 31: mixes upper half into lower half for better bit distribution
+ // Shift by 47: ensures highest bits influence final hash output
+ for (int i = 0; i < UUID_BYTES; i += 8) {
+ size_t chunk = (size_t)id.mData[i] | ((size_t)id.mData[i+1] << 8) |
+ ((size_t)id.mData[i+2] << 16) | ((size_t)id.mData[i+3] << 24) |
+ ((size_t)id.mData[i+4] << 32) | ((size_t)id.mData[i+5] << 40) |
+ ((size_t)id.mData[i+6] << 48) | ((size_t)id.mData[i+7] << 56);
+ h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47);
+ }
+ return h;
}
};
}
-// For use with boost containers.
+// For use with boost::container_hash
inline size_t hash_value(const LLUUID& id) noexcept
{
- return (size_t)id.getDigest64();
+ return std::hash<LLUUID>{}(id);
}
#endif // LL_LLUUID_H
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 67c23358ed..fbd92d089e 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -38,7 +38,8 @@ LL::WorkQueueBase::WorkQueueBase(const std::string& name, bool auto_shutdown)
{
// Register for "LLApp" events so we can implicitly close() on viewer shutdown
std::string listener_name = "WorkQueue:" + getKey();
- LLEventPumps::instance().obtain("LLApp").listen(
+ LLEventPumps* pump = LLEventPumps::getInstance();
+ pump->obtain("LLApp").listen(
listener_name,
[this](const LLSD& stat)
{
@@ -54,14 +55,25 @@ LL::WorkQueueBase::WorkQueueBase(const std::string& name, bool auto_shutdown)
// Store the listener name so we can unregister in the destructor
mListenerName = listener_name;
+ mPumpHandle = pump->getHandle();
}
}
LL::WorkQueueBase::~WorkQueueBase()
{
- if (!mListenerName.empty() && !LLEventPumps::wasDeleted())
+ if (!mListenerName.empty() && !mPumpHandle.isDead())
{
- LLEventPumps::instance().obtain("LLApp").stopListening(mListenerName);
+ // Due to shutdown order issues, use handle, not a singleton
+ // and ignore fiber issue.
+ try
+ {
+ LLEventPumps* pump = mPumpHandle.get();
+ pump->obtain("LLApp").stopListening(mListenerName);
+ }
+ catch (const boost::fibers::lock_error&)
+ {
+ // Likely mutex is down, ignore
+ }
}
}
diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h
index 573203a5b3..69f3286c1b 100644
--- a/indra/llcommon/workqueue.h
+++ b/indra/llcommon/workqueue.h
@@ -14,6 +14,7 @@
#include "llcoros.h"
#include "llexception.h"
+#include "llhandle.h"
#include "llinstancetracker.h"
#include "llinstancetrackersubclass.h"
#include "threadsafeschedule.h"
@@ -22,6 +23,9 @@
#include <functional> // std::function
#include <string>
+class LLEventPumps;
+
+
namespace LL
{
@@ -202,6 +206,8 @@ namespace LL
// Name used for the LLApp event listener (empty if not registered)
std::string mListenerName;
+ // Due to shutdown order issues, store by handle
+ LLHandle<LLEventPumps> mPumpHandle;
};
/*****************************************************************************
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
index e971e324a0..9b674d5528 100644
--- a/indra/llfilesystem/lldiskcache.cpp
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -91,6 +91,8 @@ LLDiskCache::LLDiskCache(const std::string& cache_dir,
// asset will have to be re-requested.
void LLDiskCache::purge()
{
+ LL_PROFILE_ZONE_SCOPED;
+
if (mEnableCacheDebugInfo)
{
LL_INFOS() << "Total dir size before purge is " << dirFileSize(sCacheDir) << LL_ENDL;
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 843da1eccb..1fcf70dc25 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -1064,10 +1064,9 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
if (i->first == INV_THUMBNAIL_LABEL)
{
const LLSD &thumbnail_map = i->second;
- const std::string w = INV_ASSET_ID_LABEL;
- if (thumbnail_map.has(w))
+ if (thumbnail_map.has(INV_ASSET_ID_LABEL))
{
- mThumbnailUUID = thumbnail_map[w];
+ mThumbnailUUID = thumbnail_map[INV_ASSET_ID_LABEL];
}
/* Example:
<key> asset_id </key>
@@ -1080,7 +1079,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
<integer> 1 </key>
*/
continue;
- }
+ }
if (i->first == INV_THUMBNAIL_ID_LABEL)
{
@@ -1091,10 +1090,9 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
if (i->first == INV_FAVORITE_LABEL)
{
const LLSD& favorite_map = i->second;
- const std::string w = INV_TOGGLED_LABEL;
- if (favorite_map.has(w))
+ if (favorite_map.has(INV_TOGGLED_LABEL))
{
- mFavorite = favorite_map[w].asBoolean();
+ mFavorite = favorite_map[INV_TOGGLED_LABEL].asBoolean();
}
continue;
}
@@ -1175,7 +1173,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
LLSD const &label = i->second;
if (label.isString())
{
- mType = LLAssetType::lookup(label.asString().c_str());
+ mType = LLAssetType::lookup(label.asStringRef().c_str());
}
else if (label.isInteger())
{
@@ -1190,7 +1188,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
LLSD const &label = i->second;
if (label.isString())
{
- mInventoryType = LLInventoryType::lookup(label.asString().c_str());
+ mInventoryType = LLInventoryType::lookup(label.asStringRef().c_str());
}
else if (label.isInteger())
{
@@ -1354,7 +1352,7 @@ void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
bool LLInventoryCategory::fromLLSD(const LLSD& sd)
{
- std::string w;
+ std::string_view w;
w = INV_FOLDER_ID_LABEL_WS;
if (sd.has(w))
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 7eba9494a6..e7ac6bdb31 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -615,6 +615,11 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
return false;
}
}
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS() << "Bad memory allocation in J2C KDU" << LL_ENDL;
+ }
catch (const KDUError& msg)
{
base.setLastError(msg.what());
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index dfad66040e..082ab85e51 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -912,7 +912,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai
case LL_PCODE_HOLE_CIRCLE:
case LL_PCODE_HOLE_SAME:
default:
- addHole(params, true, circle_detail, 0, hollow, 1.f);
+ addHole(params, false, circle_detail, 0, hollow, 1.f);
break;
}
}
@@ -4945,9 +4945,17 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mOctree(NULL),
mOctreeTriangles(NULL)
{
- mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
- mCenter = mExtents+2;
- *this = src;
+ try
+ {
+ mExtents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * 3);
+ mCenter = mExtents + 2;
+ *this = src;
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLVolume") << "Bad memory allocation in LLVolumeFace" << LL_ENDL;
+ }
}
LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
@@ -5165,7 +5173,7 @@ void LLVolumeFace::remap()
// Documentation for meshopt_generateVertexRemapMulti claims that remap should use vertice count
// but all examples use indice count. There are out of bounds crashes when using vertice count.
// To be on the safe side use bigger of the two.
- std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices));
+ std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices), 0);
S32 remap_vertices_count = static_cast<S32>(LLMeshOptimizer::generateRemapMultiU16(&remap[0],
mIndices,
mNumIndices,
@@ -5683,7 +5691,12 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Mikktspace::genTangSpace() failed" << LL_ENDL;
+ return false;
}
@@ -5705,7 +5718,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVOLUME") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
}
U32 stream_count = data.w.empty() ? 4 : 5;
@@ -5722,7 +5735,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVolume") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
}
}
@@ -5734,7 +5747,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
if (mNumVertices == 0)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
}
if (!data.w.empty())
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 7339454367..76d51fdad0 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -171,7 +171,6 @@ size_t LLMeshOptimizer::generateRemapMultiU32(
// but providing indices helps with removing unused vertices
U64 indeces_cmp = indices ? index_count : vertex_count;
- // meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
}
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index ebafc53a4d..86b36315dc 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -276,7 +276,7 @@ void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &h
// Provide some fallback for agents that return errors
void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
{
- std::map<LLUUID,LLAvatarName>::iterator existing = mCache.find(agent_id);
+ cache_t::iterator existing = mCache.find(agent_id);
if (existing == mCache.end())
{
// there is no existing cache entry, so make a temporary name from legacy
@@ -311,7 +311,7 @@ void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName&
bool updated_account = true; // assume obsolete value for new arrivals by default
- std::map<LLUUID, LLAvatarName>::iterator it = mCache.find(agent_id);
+ cache_t::iterator it = mCache.find(agent_id);
if (it != mCache.end()
&& (*it).second.getAccountName() == av_name.getAccountName())
{
@@ -418,7 +418,7 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
// Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy
// protocol, we do not get an expiration date for each name and there's no reason to ask the
// data again and again so we set the expiration time to the largest value admissible.
- std::map<LLUUID,LLAvatarName>::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id);
+ cache_t::iterator av_record = LLAvatarNameCache::getInstance()->mCache.find(agent_id);
LLAvatarName& av_name = av_record->second;
av_name.setExpires(MAX_UNREFRESHED_TIME);
}
@@ -631,7 +631,7 @@ bool LLAvatarNameCache::getName(const LLUUID& agent_id, LLAvatarName *av_name)
if (mRunning)
{
// ...only do immediate lookups when cache is running
- std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id);
+ cache_t::iterator it = mCache.find(agent_id);
if (it != mCache.end())
{
*av_name = it->second;
@@ -682,7 +682,7 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::getNameCallback(cons
if (mRunning)
{
// ...only do immediate lookups when cache is running
- std::map<LLUUID,LLAvatarName>::iterator it = mCache.find(agent_id);
+ cache_t::iterator it = mCache.find(agent_id);
if (it != mCache.end())
{
const LLAvatarName& av_name = it->second;
@@ -753,13 +753,11 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
LLUUID LLAvatarNameCache::findIdByName(const std::string& name)
{
- std::map<LLUUID, LLAvatarName>::iterator it;
- std::map<LLUUID, LLAvatarName>::iterator end = mCache.end();
- for (it = mCache.begin(); it != end; ++it)
+ for (const auto& [id, avatar_name] : mCache)
{
- if (it->second.getUserName() == name)
+ if (avatar_name.getUserName() == name)
{
- return it->first;
+ return id;
}
}
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 0ddaee2aa1..6743943495 100644
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -30,8 +30,10 @@
#include "llavatarname.h" // for convenience
#include "llsingleton.h"
+#include "lluuid.h"
#include <boost/signals2.hpp>
#include <set>
+#include <unordered_map>
class LLSD;
class LLUUID;
@@ -161,23 +163,23 @@ private:
std::string mNameLookupURL;
// Accumulated agent IDs for next query against service
- typedef std::set<LLUUID> ask_queue_t;
+ using ask_queue_t = std::set<LLUUID>;
ask_queue_t mAskQueue;
// Agent IDs that have been requested, but with no reply.
// Maps agent ID to frame time request was made.
- typedef std::map<LLUUID, F64> pending_queue_t;
+ using pending_queue_t = std::unordered_map<LLUUID, F64>;
pending_queue_t mPendingQueue;
// Callbacks to fire when we received a name.
// May have multiple callbacks for a single ID, which are
// represented as multiple slots bound to the signal.
// Avoid copying signals via pointers.
- typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
+ using signal_map_t = std::unordered_map<LLUUID, callback_signal_t*>;
signal_map_t mSignalMap;
// The cache at last, i.e. avatar names we know about.
- typedef std::map<LLUUID, LLAvatarName> cache_t;
+ using cache_t = std::unordered_map<LLUUID, LLAvatarName>;
cache_t mCache;
// Time when unrefreshed cached names were checked last.
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 56dfaef873..95b7bb8c3d 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -179,12 +179,11 @@ void ReplySender::flush()
}
}
-
-typedef std::set<LLUUID> AskQueue;
-typedef std::list<PendingReply*> ReplyQueue;
-typedef std::map<LLUUID,U32> PendingQueue;
-typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
-typedef std::map<std::string, LLUUID> ReverseCache;
+using AskQueue = std::set<LLUUID>;
+using ReplyQueue = std::list<PendingReply*>;
+using PendingQueue = std::unordered_map<LLUUID, U32>;
+using Cache = std::unordered_map<LLUUID, LLCacheNameEntry*>;
+using ReverseCache = std::unordered_map<std::string, LLUUID>;
class LLCacheName::Impl
{
@@ -214,7 +213,7 @@ public:
Impl(LLMessageSystem* msg);
~Impl();
- bool getName(const LLUUID& id, std::string& first, std::string& last, std::map<std::string, std::string>& default_names);
+ bool getName(const LLUUID& id, std::string& first, std::string& last, cache_map_t& default_names);
boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
void addPending(const LLUUID& id, const LLHost& host);
@@ -401,7 +400,7 @@ void LLCacheName::exportFile(std::ostream& ostr)
}
-bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, std::map<std::string, std::string>& default_names)
+bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, cache_map_t &default_names)
{
if(id.isNull())
{
diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h
index 609387b6de..a333eac0f5 100644
--- a/indra/llmessage/llcachename.h
+++ b/indra/llmessage/llcachename.h
@@ -136,7 +136,8 @@ public:
void localizeCacheName(std::string key, std::string value);
private:
- std::map<std::string, std::string> mCacheName;
+ using cache_map_t = std::unordered_map<std::string, std::string>;
+ cache_map_t mCacheName;
class Impl;
Impl& impl;
diff --git a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp
index 78876f9f36..b7c4b5e591 100644
--- a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp
+++ b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.cpp
@@ -75,10 +75,7 @@ LLCDResult LLConvexDecompositionVHACD::quitSystem()
LLConvexDecompositionVHACD::LLConvexDecompositionVHACD()
{
- //Create our vhacd instance and setup default parameters
- mVHACD = VHACD::CreateVHACD();
-
- mVHACDParameters.m_callback = &mVHACDCallback;
+ // Setup default parameters
mVHACDParameters.m_logger = &mVHACDLogger;
mDecompStages[0].mName = "Analyze";
@@ -206,27 +203,33 @@ LLConvexDecompositionVHACD::LLConvexDecompositionVHACD()
LLConvexDecompositionVHACD::~LLConvexDecompositionVHACD()
{
- mBoundDecomp = nullptr;
- mDecompData.clear();
-
- mVHACD->Release();
+ {
+ LLMutexLock lock(&mDecompDataMutex);
+ mBoundDecompID = INVALID_DECOMP_ID;
+ mDecompData.clear();
+ }
}
void LLConvexDecompositionVHACD::genDecomposition(int& decomp)
{
- int new_decomp_id = static_cast<int>(mDecompData.size()) + 1;
- mDecompData[new_decomp_id] = LLDecompData();
- decomp = new_decomp_id;
+ LLMutexLock lock(&mDecompDataMutex);
+
+ mDecompData[mNextDecompID] = std::make_shared<LLDecompData>();
+ decomp = mNextDecompID;
+
+ ++mNextDecompID; // Increment decomposition ID. Never reuse to protect downstream consumers from misuse
}
void LLConvexDecompositionVHACD::deleteDecomposition(int decomp)
{
+ LLMutexLock lock(&mDecompDataMutex);
+
auto iter = mDecompData.find(decomp);
if (iter != mDecompData.end())
{
- if (mBoundDecomp == &iter->second)
+ if (mBoundDecompID == decomp)
{
- mBoundDecomp = nullptr;
+ mBoundDecompID = INVALID_DECOMP_ID;
}
mDecompData.erase(iter);
}
@@ -234,29 +237,48 @@ void LLConvexDecompositionVHACD::deleteDecomposition(int decomp)
void LLConvexDecompositionVHACD::bindDecomposition(int decomp)
{
- auto iter = mDecompData.find(decomp);
- if (iter != mDecompData.end())
+ LLMutexLock lock(&mDecompDataMutex);
+
+ if (mDecompData.contains(decomp))
{
- mBoundDecomp = &iter->second;
+ mBoundDecompID = decomp;
}
else
{
LL_WARNS() << "Failed to bind unknown decomposition: " << decomp << LL_ENDL;
- mBoundDecomp = nullptr;
+ mBoundDecompID = INVALID_DECOMP_ID;
}
}
+LLConvexDecompositionVHACD::data_ptr_t LLConvexDecompositionVHACD::getBoundDecomp()
+{
+ data_ptr_t bound_decomp;
+ {
+ LLMutexLock lock(&mDecompDataMutex);
+ auto it = mDecompData.find(mBoundDecompID);
+ if (it != mDecompData.end())
+ {
+ bound_decomp = it->second; // Take a copy of the shared_ptr to avoid potential deletion
+ }
+ }
+ return bound_decomp;
+}
+
LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, float val)
{
- if (name == std::string("Num Hulls"))
+ LLMutexLock lock(&mParamsMutex);
+
+ using namespace std::literals;
+
+ if (name == "Num Hulls"sv)
{
mVHACDParameters.m_maxConvexHulls = llclamp(ll_round(val), 1, MAX_HULLS);
}
- else if (name == std::string("Num Vertices"))
+ else if (name == "Num Vertices"sv)
{
mVHACDParameters.m_maxNumVerticesPerCH = llclamp(ll_round(val), 3, MAX_VERTICES_PER_HULL);
}
- else if (name == std::string("Error Tolerance"))
+ else if (name == "Error Tolerance"sv)
{
mVHACDParameters.m_minimumVolumePercentErrorAllowed = val;
}
@@ -270,11 +292,15 @@ LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, bool val)
LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val)
{
- if (name == std::string("Fill Mode"))
+ LLMutexLock lock(&mParamsMutex);
+
+ using namespace std::literals;
+
+ if (name == "Fill Mode"sv)
{
mVHACDParameters.m_fillMode = (VHACD::FillMode)val;
}
- else if (name == std::string("Voxel Resolution"))
+ else if (name == "Voxel Resolution"sv)
{
mVHACDParameters.m_resolution = val;
}
@@ -283,19 +309,21 @@ LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val)
LLCDResult LLConvexDecompositionVHACD::setMeshData( const LLCDMeshData* data, bool vertex_based )
{
- if (!mBoundDecomp)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
- return mBoundDecomp->mSourceMesh.from(data, vertex_based);
+ return bound_decomp->mSourceMesh.from(data, vertex_based);
}
LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackFunc callback )
{
if (stage == 0)
{
- mVHACDCallback.setCallbackFunc(callback);
+ LLMutexLock lock(&mParamsMutex);
+ mCurrentCallbackFunc = callback;
return LLCD_OK;
}
else
@@ -306,44 +334,68 @@ LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackF
LLCDResult LLConvexDecompositionVHACD::executeStage(int stage)
{
- if (!mBoundDecomp)
+ if (stage != 0)
+ {
+ return LLCD_INVALID_STAGE;
+ }
+
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
- if (stage != 0)
+ bound_decomp->mDecomposedHulls.clear();
+
+ const auto& decomp_mesh = bound_decomp->mSourceMesh;
+
+ VHACDCallback callbacks;
+ VHACD::IVHACD::Parameters current_params;
{
- return LLCD_INVALID_STAGE;
+ LLMutexLock lock(&mParamsMutex);
+
+ current_params = mVHACDParameters;
+ callbacks.setCallbackFunc(mCurrentCallbackFunc);
+ }
+ current_params.m_callback = &callbacks;
+
+ auto vhacd_impl = VHACD::CreateVHACD();
+ if (!vhacd_impl)
+ {
+ LL_WARNS() << "Failed to create VHACD instance" << LL_ENDL;
+ return LLCD_NULL_PTR;
}
- mBoundDecomp->mDecomposedHulls.clear();
- const auto& decomp_mesh = mBoundDecomp->mSourceMesh;
- if (!mVHACD->Compute((const double* const)decomp_mesh.mVertices.data(), static_cast<uint32_t>(decomp_mesh.mVertices.size()), (const uint32_t* const)decomp_mesh.mIndices.data(), static_cast<uint32_t>(decomp_mesh.mIndices.size()), mVHACDParameters))
+ if (!vhacd_impl->Compute((const double*)decomp_mesh.mVertices.data(), static_cast<uint32_t>(decomp_mesh.mVertices.size()),
+ (const uint32_t*)decomp_mesh.mIndices.data(), static_cast<uint32_t>(decomp_mesh.mIndices.size()),
+ current_params))
{
+ vhacd_impl->Release();
return LLCD_INVALID_HULL_DATA;
}
- uint32_t num_nulls = mVHACD->GetNConvexHulls();
- if (num_nulls == 0)
+ uint32_t num_convex_hulls = vhacd_impl->GetNConvexHulls();
+ if (num_convex_hulls == 0)
{
+ vhacd_impl->Release();
return LLCD_INVALID_HULL_DATA;
}
- for (uint32_t i = 0; num_nulls > i; ++i)
+ for (uint32_t i = 0; num_convex_hulls > i; ++i)
{
VHACD::IVHACD::ConvexHull ch;
- if (!mVHACD->GetConvexHull(i, ch))
+ if (!vhacd_impl->GetConvexHull(i, ch))
continue;
LLConvexMesh out_mesh;
out_mesh.setVertices(ch.m_points);
out_mesh.setIndices(ch.m_triangles);
- mBoundDecomp->mDecomposedHulls.push_back(std::move(out_mesh));
+ bound_decomp->mDecomposedHulls.push_back(std::move(out_mesh));
}
- mVHACD->Clean();
+ vhacd_impl->Release();
return LLCD_OK;
}
@@ -351,19 +403,21 @@ LLCDResult LLConvexDecompositionVHACD::executeStage(int stage)
LLCDResult LLConvexDecompositionVHACD::buildSingleHull()
{
LL_INFOS() << "Building single hull mesh" << LL_ENDL;
- if (!mBoundDecomp || mBoundDecomp->mSourceMesh.mVertices.empty())
+
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp || bound_decomp->mSourceMesh.mVertices.empty())
{
return LLCD_NULL_PTR;
}
- mBoundDecomp->mSingleHullMesh.clear();
+ bound_decomp->mSingleHullMesh.clear();
VHACD::QuickHull quickhull;
- uint32_t num_tris = quickhull.ComputeConvexHull(mBoundDecomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL);
+ uint32_t num_tris = quickhull.ComputeConvexHull(bound_decomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL);
if (num_tris > 0)
{
- mBoundDecomp->mSingleHullMesh.setVertices(quickhull.GetVertices());
- mBoundDecomp->mSingleHullMesh.setIndices(quickhull.GetIndices());
+ bound_decomp->mSingleHullMesh.setVertices(quickhull.GetVertices());
+ bound_decomp->mSingleHullMesh.setIndices(quickhull.GetIndices());
return LLCD_OK;
}
@@ -373,29 +427,31 @@ LLCDResult LLConvexDecompositionVHACD::buildSingleHull()
int LLConvexDecompositionVHACD::getNumHullsFromStage(int stage)
{
- if (!mBoundDecomp || stage != 0)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp || stage != 0)
{
return 0;
}
- return narrow(mBoundDecomp->mDecomposedHulls.size());
+ return narrow(bound_decomp->mDecomposedHulls.size());
}
LLCDResult LLConvexDecompositionVHACD::getSingleHull( LLCDHull* hullOut )
{
memset( hullOut, 0, sizeof(LLCDHull) );
- if (!mBoundDecomp)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
- if (mBoundDecomp->mSingleHullMesh.vertices.empty())
+ if (bound_decomp->mSingleHullMesh.vertices.empty())
{
return LLCD_INVALID_HULL_DATA;
}
- mBoundDecomp->mSingleHullMesh.to(hullOut);
+ bound_decomp->mSingleHullMesh.to(hullOut);
return LLCD_OK;
}
@@ -403,7 +459,8 @@ LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LL
{
memset( hullOut, 0, sizeof(LLCDHull) );
- if (!mBoundDecomp)
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
@@ -413,19 +470,21 @@ LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LL
return LLCD_INVALID_STAGE;
}
- if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull)
+ if (bound_decomp->mDecomposedHulls.empty() || S32(bound_decomp->mDecomposedHulls.size()) <= hull)
{
return LLCD_REQUEST_OUT_OF_RANGE;
}
- mBoundDecomp->mDecomposedHulls[hull].to(hullOut);
+ bound_decomp->mDecomposedHulls[hull].to(hullOut);
return LLCD_OK;
}
LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut )
{
memset( meshDataOut, 0, sizeof(LLCDMeshData));
- if (!mBoundDecomp)
+
+ data_ptr_t bound_decomp = getBoundDecomp();
+ if (!bound_decomp)
{
return LLCD_NULL_PTR;
}
@@ -435,12 +494,12 @@ LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LL
return LLCD_INVALID_STAGE;
}
- if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull)
+ if (bound_decomp->mDecomposedHulls.empty() || S32(bound_decomp->mDecomposedHulls.size()) <= hull)
{
return LLCD_REQUEST_OUT_OF_RANGE;
}
- mBoundDecomp->mDecomposedHulls[hull].to(meshDataOut);
+ bound_decomp->mDecomposedHulls[hull].to(meshDataOut);
return LLCD_OK;
}
diff --git a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h
index 675356629c..27c867704e 100644
--- a/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h
+++ b/indra/llphysicsextensionsos/llconvexdecompositionvhacd.h
@@ -31,6 +31,7 @@
#include "llconvexdecomposition.h"
#include "llsingleton.h"
#include "llmath.h"
+#include "llmutex.h"
#include <vector>
@@ -323,14 +324,25 @@ private:
std::vector<LLConvexMesh> mDecomposedHulls;
};
- std::unordered_map<int, LLDecompData> mDecompData;
+ using data_ptr_t = std::shared_ptr<LLDecompData>;
- LLDecompData* mBoundDecomp = nullptr;
+ data_ptr_t getBoundDecomp();
+
+ // MUST lock before accessing mDecompData mBoundDecompID or mNextDecompID
+ LLMutex mDecompDataMutex;
+
+ static constexpr int INVALID_DECOMP_ID = -1;
+
+ int mBoundDecompID = INVALID_DECOMP_ID;
+ int mNextDecompID = 0; // Only for use inside genDecomposition.
+
+ std::unordered_map<int, data_ptr_t> mDecompData;
- VHACD::IVHACD* mVHACD = nullptr;
- VHACDCallback mVHACDCallback;
VHACDLogger mVHACDLogger;
+
+ LLMutex mParamsMutex;
VHACD::IVHACD::Parameters mVHACDParameters;
+ llcdCallbackFunc mCurrentCallbackFunc;
LLConvexMesh mMeshFromHullData;
LLConvexMesh mSingleHullMeshFromMeshData;
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 930222e3db..b2cd1dc597 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -214,7 +214,7 @@ std::string LLGLTFMaterial::asJSON(bool prettyprint) const
// to WriteGltfSceneToStream in the viewer.
gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false);
- return str.str();
+ return std::move(str).str();
}
void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h
index cec0965441..3ed80eaab9 100644
--- a/indra/llprimitive/llmaterialid.h
+++ b/indra/llprimitive/llmaterialid.h
@@ -63,15 +63,11 @@ public:
static const LLMaterialID null;
- // Returns a 64 bits digest of the material Id, by XORing its two 64 bits
- // long words. HB
- inline U64 getDigest64() const
- {
- U64* tmp = (U64*)mID;
- return tmp[0] ^ tmp[1];
- }
-
private:
+ // definitions follow class
+ friend std::hash<LLMaterialID>;
+ friend size_t hash_value(const LLMaterialID&) noexcept;
+
void parseFromBinary(const LLSD::Binary& pMaterialID);
int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const;
@@ -85,15 +81,27 @@ namespace std
{
inline size_t operator()(const LLMaterialID& id) const noexcept
{
- return (size_t)id.getDigest64();
+ size_t h = 0;
+ // Golden ratio hash with avalanche mixing
+ // Process 8 bytes at a time by manually constructing 64-bit values
+ // Shift by 31: mixes upper half into lower half for better bit distribution
+ // Shift by 47: ensures highest bits influence final hash output
+ for (int i = 0; i < MATERIAL_ID_SIZE; i += 8) {
+ size_t chunk = (size_t)id.mID[i] | ((size_t)id.mID[i + 1] << 8) |
+ ((size_t)id.mID[i+2] << 16) | ((size_t)id.mID[i+3] << 24) |
+ ((size_t)id.mID[i+4] << 32) | ((size_t)id.mID[i+5] << 40) |
+ ((size_t)id.mID[i + 6] << 48) | ((size_t)id.mID[i + 7] << 56);
+ h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47);
+ }
+ return h;
}
};
}
-// For use with boost containers.
+// For use with boost::container_hash
inline size_t hash_value(const LLMaterialID& id) noexcept
{
- return (size_t)id.getDigest64();
+ return std::hash<LLMaterialID>{}(id);
}
#endif // LL_LLMATERIALID_H
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index a9b3a944ee..f7600e40a3 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -27,13 +27,14 @@
#ifndef LL_LLFONTFREETYPE_H
#define LL_LLFONTFREETYPE_H
-#include <boost/unordered_map.hpp>
#include "llpointer.h"
#include "llstl.h"
#include "llimagegl.h"
#include "llfontbitmapcache.h"
+#include <unordered_map>
+
// Hack. FT_Face is just a typedef for a pointer to a struct,
// but there's no simple forward declarations file for FreeType,
// and the main include file is 200K.
@@ -184,7 +185,7 @@ private:
fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
// *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique)
- typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
+ typedef std::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
mutable LLFontBitmapCache* mFontBitmapCachep;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 25277f1341..5357a79bae 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2429,7 +2429,7 @@ void clear_glerror()
//
// Static members
-boost::unordered_map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
+std::unordered_map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default
GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default
@@ -2471,7 +2471,7 @@ void LLGLState::resetTextureStates()
void LLGLState::dumpStates()
{
LL_INFOS("RenderState") << "GL States:" << LL_ENDL;
- for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+ for (std::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
iter != sStateMap.end(); ++iter)
{
LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"true":"false") << LL_ENDL;
@@ -2503,7 +2503,7 @@ void LLGLState::checkStates(GLboolean writeAlpha)
//llassert_always(colorMask[2]);
// llassert_always(colorMask[3] == writeAlpha);
- for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+ for (std::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
iter != sStateMap.end(); ++iter)
{
LLGLenum state = iter->first;
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index dd30c82981..469802657a 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -31,7 +31,7 @@
#include <functional>
#include <string>
-#include <boost/unordered_map.hpp>
+#include <unordered_map>
#include <list>
#include "llglheaders.h"
@@ -261,7 +261,7 @@ public:
static void checkStates(GLboolean writeAlpha = GL_TRUE);
protected:
- static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
+ static std::unordered_map<LLGLenum, LLGLboolean> sStateMap;
public:
enum { CURRENT_STATE = -2, DISABLED_STATE = 0, ENABLED_STATE = 1 };
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index f609fe8105..da913ee9d6 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -239,7 +239,7 @@ void LLFloater::initClass()
}
// defaults for floater param block pulled from widgets/floater.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(&typeid(LLFloater::Params), "floater");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterFloaterParams(typeid(LLFloater::Params), "floater");
LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
: LLPanel(), // intentionally do not pass params here, see initFromParams
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index a818e72f59..c18495ce71 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -40,9 +40,9 @@
LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;
LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
-std::map<std::string, std::string, std::less<>> LLFloaterReg::sGroupMap;
+LLFloaterReg::group_map_t LLFloaterReg::sGroupMap;
bool LLFloaterReg::sBlockShowFloaters = false;
-std::set<std::string, std::less<>> LLFloaterReg::sAlwaysShowableList;
+LLFloaterReg::always_showable_t LLFloaterReg::sAlwaysShowableList;
static LLFloaterRegListener sFloaterRegListener;
@@ -96,11 +96,8 @@ LLFloater* LLFloaterReg::getLastFloaterCascading()
candidate_rect.mTop = 100000;
LLFloater* candidate_floater = NULL;
- std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
- for( ; it != it_end; ++it)
+ for (const auto& [floater_name, group_name] : sGroupMap)
{
- const std::string& group_name = it->second;
-
instance_list_t& instances = sInstanceMap[group_name];
for (LLFloater* inst : instances)
@@ -604,17 +601,11 @@ U32 LLFloaterReg::getVisibleFloaterInstanceCount()
{
U32 count = 0;
- std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
- for( ; it != it_end; ++it)
+ for (const auto& [floater_name, group_name] : sGroupMap)
{
- const std::string& group_name = it->second;
-
instance_list_t& instances = sInstanceMap[group_name];
-
- for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
+ for (LLFloater* inst : instances)
{
- LLFloater* inst = *iter;
-
if (inst->getVisible() && !inst->isMinimized())
{
count++;
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 24d1476dda..71a11b6f42 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -29,9 +29,11 @@
/// llcommon
#include "llrect.h"
#include "llsd.h"
+#include "llstl.h"
#include <functional>
#include <list>
+#include <unordered_set>
//*******************************************************
//
@@ -51,26 +53,29 @@ public:
// 2) We can change the key of a floater without altering the list.
typedef std::list<LLFloater*> instance_list_t;
typedef const instance_list_t const_instance_list_t;
- typedef std::map<std::string, instance_list_t, std::less<>> instance_map_t;
+ typedef std::unordered_map<std::string, instance_list_t, ll::string_hash, std::equal_to<>> instance_map_t;
struct BuildData
{
LLFloaterBuildFunc mFunc;
std::string mFile;
};
- typedef std::map<std::string, BuildData, std::less<>> build_map_t;
+ typedef std::unordered_map<std::string, BuildData, ll::string_hash, std::equal_to<>> build_map_t;
private:
friend class LLFloaterRegListener;
static instance_list_t sNullInstanceList;
static instance_map_t sInstanceMap;
static build_map_t sBuildMap;
- static std::map<std::string, std::string, std::less<>> sGroupMap;
+
+ using group_map_t = std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>>;
+ static group_map_t sGroupMap;
static bool sBlockShowFloaters;
/**
* Defines list of floater names that can be shown despite state of sBlockShowFloaters.
*/
- static std::set<std::string, std::less<>> sAlwaysShowableList;
+ using always_showable_t = std::unordered_set<std::string, ll::string_hash, std::equal_to<>>;
+ static always_showable_t sAlwaysShowableList;
public:
// Registration
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 878f1cb856..dafbca7433 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -28,6 +28,7 @@
#include "llflashtimer.h"
#include "linden_common.h"
+#include "llapp.h"
#include "llfolderviewitem.h"
#include "llfolderview.h"
#include "llfolderviewmodel.h"
@@ -1884,6 +1885,11 @@ void LLFolderViewFolder::updateHasFavorites(bool new_childs_value)
void LLFolderViewFolder::onIdleUpdateFavorites(void* data)
{
LLFolderViewFolder* self = reinterpret_cast<LLFolderViewFolder*>(data);
+ if (gDisconnected || !self)
+ {
+ return;
+ }
+
if (self->mFavoritesDirtyFlags == FAVORITE_CLEANUP)
{
// parent or child already processed the update, clean the callback
@@ -2359,9 +2365,10 @@ bool LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
{
// navigating is going to destroy views and change children
// delay it untill handleDoubleClick processing is complete
- doOnIdleOneTime([this]()
- {
- getViewModelItem()->navigateToFolder(false);
+ LLPointer<LLFolderViewModelItem> view_model_item = getViewModelItem();
+ doOnIdleOneTime([view_model_item]() mutable
+ {;
+ view_model_item->navigateToFolder(false);
});
}
return true;
diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h
index 953963b683..40a3e439a6 100644
--- a/indra/llui/llfunctorregistry.h
+++ b/indra/llui/llfunctorregistry.h
@@ -29,8 +29,9 @@
#define LL_LLFUNCTORREGISTRY_H
#include <string>
-#include <map>
+#include <unordered_map>
+#include "llstring.h"
#include "llsd.h"
#include "llsingleton.h"
@@ -56,7 +57,7 @@ class LLFunctorRegistry : public LLSingleton<LLFunctorRegistry<FUNCTOR_TYPE> >
public:
typedef FUNCTOR_TYPE ResponseFunctor;
- typedef typename std::map<std::string, FUNCTOR_TYPE> FunctorMap;
+ typedef typename std::unordered_map<std::string, FUNCTOR_TYPE, ll::string_hash, std::equal_to<>> FunctorMap;
bool registerFunctor(const std::string& name, ResponseFunctor f)
{
diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h
index 70fc2c20d5..9d9c8f964c 100644
--- a/indra/llui/llkeywords.h
+++ b/indra/llui/llkeywords.h
@@ -232,7 +232,7 @@ protected:
token_by_first_char_map_t mLineTokenByFirstChar;
token_by_first_char_map_t mDelimiterTokenByFirstChar;
- typedef std::map<std::string, std::string, std::less<>> element_attributes_t;
+ typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> element_attributes_t;
typedef element_attributes_t::const_iterator attribute_iterator_t;
element_attributes_t mAttributes;
std::string getAttribute(std::string_view key);
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 0ffe6cff5e..56475a2d8d 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1424,6 +1424,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN
// this function is called once at construction time, after the object is constructed.
void LLNotifications::initSingleton()
{
+ LL_PROFILE_ZONE_SCOPED;
loadTemplates();
loadVisibilityRules();
createDefaultChannels();
@@ -1436,6 +1437,8 @@ void LLNotifications::cleanupSingleton()
void LLNotifications::createDefaultChannels()
{
+ LL_PROFILE_ZONE_SCOPED;
+
LL_INFOS("Notifications") << "Generating default notification channels" << LL_ENDL;
// now construct the various channels AFTER loading the notifications,
// because the history channel is going to rewrite the stored notifications file
@@ -1578,6 +1581,8 @@ void addPathIfExists(const std::string& new_path, std::vector<std::string>& path
bool LLNotifications::loadTemplates()
{
+ LL_PROFILE_ZONE_SCOPED;
+
LL_INFOS("Notifications") << "Reading notifications template" << LL_ENDL;
// Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it
// output all relevant pathnames instead of just the ones from the most
@@ -1663,6 +1668,8 @@ bool LLNotifications::loadTemplates()
bool LLNotifications::loadVisibilityRules()
{
+ LL_PROFILE_ZONE_SCOPED;
+
const std::string xml_filename = "notification_visibility.xml";
// Note that here we're looking for the "en" version, the default
// language, rather than the most localized version of this file.
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index c7c7435be2..ea1cb7f638 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -946,7 +946,7 @@ public:
typedef std::vector<std::string> TemplateNames;
TemplateNames getTemplateNames() const; // returns a list of notification names
- typedef std::map<std::string, LLNotificationTemplatePtr, std::less<>> TemplateMap;
+ typedef std::unordered_map<std::string, LLNotificationTemplatePtr, ll::string_hash, std::equal_to<>> TemplateMap;
TemplateMap::const_iterator templatesBegin() { return mTemplates.begin(); }
TemplateMap::const_iterator templatesEnd() { return mTemplates.end(); }
@@ -992,7 +992,7 @@ private:
LLNotificationMap mUniqueNotifications;
- typedef std::map<std::string, std::string, std::less<>> GlobalStringMap;
+ typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> GlobalStringMap;
GlobalStringMap mGlobalStrings;
bool mIgnoreAllNotifications;
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index fe861dc719..a928997c7d 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -250,7 +250,7 @@ private:
LLButton* mDefaultBtn;
LLUIString mLabel;
- typedef std::map<std::string, std::string, std::less<>> ui_string_map_t;
+ typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> ui_string_map_t;
ui_string_map_t mUIStrings;
@@ -292,7 +292,7 @@ public:
}
private:
- typedef std::map< std::string, LLPanelClassCreatorFunc, std::less<>> param_name_map_t;
+ typedef std::unordered_map<std::string, LLPanelClassCreatorFunc, ll::string_hash, std::equal_to<>> param_name_map_t;
param_name_map_t mPanelClassesNames;
};
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index 2aff434612..1dbd9f5b0c 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -67,7 +67,7 @@ protected:
LLSD mPayload; // stores data that this item represents in the radio group
};
-static LLWidgetNameRegistry::StaticRegistrar register_radio_item(&typeid(LLRadioGroup::ItemParams), "radio_item");
+static LLWidgetNameRegistry::StaticRegistrar register_radio_item(typeid(LLRadioGroup::ItemParams), "radio_item");
LLRadioGroup::Params::Params()
: allow_deselect("allow_deselect"),
diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp
index 111c732548..f00d876b2b 100644
--- a/indra/llui/llresmgr.cpp
+++ b/indra/llui/llresmgr.cpp
@@ -54,11 +54,9 @@ char LLResMgr::getDecimalPoint() const
return decimal;
}
-char LLResMgr::getThousandsSeparator() const
+std::string LLResMgr::getThousandsSeparator() const
{
- char separator = localeconv()->thousands_sep[0];
-
- return separator;
+ return localeconv()->thousands_sep;
}
char LLResMgr::getMonetaryDecimalPoint() const
@@ -68,11 +66,9 @@ char LLResMgr::getMonetaryDecimalPoint() const
return decimal;
}
-char LLResMgr::getMonetaryThousandsSeparator() const
+std::string LLResMgr::getMonetaryThousandsSeparator() const
{
- char separator = localeconv()->mon_thousands_sep[0];
-
- return separator;
+ return localeconv()->mon_thousands_sep;
}
@@ -85,7 +81,7 @@ std::string LLResMgr::getMonetaryString( S32 input ) const
struct lconv *conv = localeconv();
char* negative_sign = conv->negative_sign;
- char separator = getMonetaryThousandsSeparator();
+ std::string separator = getMonetaryThousandsSeparator();
char* grouping = conv->mon_grouping;
// Note on mon_grouping:
@@ -135,10 +131,7 @@ std::string LLResMgr::getMonetaryString( S32 input ) const
}
S32 group_count = cur_group;
- char reversed_output[20] = ""; /* Flawfinder: ignore */
- char forward_output[20] = ""; /* Flawfinder: ignore */
- S32 output_pos = 0;
-
+ std::string formatted;
cur_group = 0;
S32 pos = static_cast<S32>(digits.size()) - 1;
S32 count_within_group = 0;
@@ -148,7 +141,7 @@ std::string LLResMgr::getMonetaryString( S32 input ) const
if( count_within_group > groupings[cur_group] )
{
count_within_group = 1;
- reversed_output[ output_pos++ ] = separator;
+ formatted = separator + formatted;
if( (cur_group + 1) >= group_count )
{
@@ -160,28 +153,19 @@ std::string LLResMgr::getMonetaryString( S32 input ) const
cur_group++;
}
}
- reversed_output[ output_pos++ ] = digits[pos--];
+ formatted = std::string(1, digits[pos--]) + formatted;
}
while( pos >= 0 )
{
- reversed_output[ output_pos++ ] = digits[pos--];
- }
-
-
- reversed_output[ output_pos ] = '\0';
- forward_output[ output_pos ] = '\0';
-
- for( S32 i = 0; i < output_pos; i++ )
- {
- forward_output[ output_pos - 1 - i ] = reversed_output[ i ];
+ formatted = std::string(1, digits[pos--]) + formatted;
}
if( negative_before )
{
output.append( negative_sign );
}
- output.append( forward_output );
+ output.append( formatted );
if( negative_after )
{
output.append( negative_sign );
@@ -210,11 +194,11 @@ void LLResMgr::getIntegerString( std::string& output, S32 input ) const
{
if (fraction == remaining_count)
{
- fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator());
+ fraction_string = llformat_to_utf8("%d", fraction) + getThousandsSeparator();
}
else
{
- fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator());
+ fraction_string = llformat_to_utf8("%3.3d", fraction) + getThousandsSeparator();
}
output = fraction_string + output;
}
diff --git a/indra/llui/llresmgr.h b/indra/llui/llresmgr.h
index 7ad6659a44..8ceb584ec5 100644
--- a/indra/llui/llresmgr.h
+++ b/indra/llui/llresmgr.h
@@ -49,10 +49,10 @@ public:
LLLOCALE_ID getLocale() const { return mLocale; }
char getDecimalPoint() const;
- char getThousandsSeparator() const;
+ std::string getThousandsSeparator() const;
char getMonetaryDecimalPoint() const;
- char getMonetaryThousandsSeparator() const;
+ std::string getMonetaryThousandsSeparator() const;
std::string getMonetaryString( S32 input ) const;
void getIntegerString( std::string& output, S32 input ) const;
diff --git a/indra/llui/llrngwriter.cpp b/indra/llui/llrngwriter.cpp
index 1b4008cff2..5b0d2315c1 100644
--- a/indra/llui/llrngwriter.cpp
+++ b/indra/llui/llrngwriter.cpp
@@ -94,7 +94,7 @@ void LLRNGWriter::addDefinition(const std::string& type_name, const LLInitParam:
block.inspectBlock(*this);
// add includes for all possible children
- const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
+ const std::type_index& type = *LLWidgetTypeRegistry::instance().getValue(type_name);
const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
// add include declarations for all valid children
diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp
index a4510d1fc2..b5ba466750 100644
--- a/indra/llui/llscrolllistcolumn.cpp
+++ b/indra/llui/llscrolllistcolumn.cpp
@@ -39,7 +39,7 @@
const S32 MIN_COLUMN_WIDTH = 20;
// defaults for LLScrollColumnHeader param block pulled from widgets/scroll_column_header.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(&typeid(LLScrollColumnHeader::Params), "scroll_column_header");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterColumnHeaderParams(typeid(LLScrollColumnHeader::Params), "scroll_column_header");
//---------------------------------------------------------------------------
// LLScrollColumnHeader
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 2079ff17fc..24ae5c09e9 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -129,7 +129,7 @@ struct LLTextBase::line_end_compare
//
// register LLTextBase::Params under name "textbase"
-static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(&typeid(LLTextBase::Params), "textbase");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(typeid(LLTextBase::Params), "textbase");
LLTextBase::LineSpacingParams::LineSpacingParams()
: multiple("multiple", 1.f),
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index 74f03618cf..c5b1b5ba1d 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -129,7 +129,7 @@ void LLToolTipView::drawStickyRect()
}
// defaults for floater param block pulled from widgets/floater.xml
-static LLWidgetNameRegistry::StaticRegistrar sRegisterInspectorParams(&typeid(LLInspector::Params), "inspector");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterInspectorParams(typeid(LLInspector::Params), "inspector");
//
// LLToolTip
diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h
index c5d01e6f8d..4dba4c5c3e 100644
--- a/indra/llui/lltrans.h
+++ b/indra/llui/lltrans.h
@@ -125,7 +125,7 @@ public:
}
private:
- typedef std::map<std::string, LLTransTemplate, std::less<>> template_map_t;
+ typedef std::unordered_map<std::string, LLTransTemplate, ll::string_hash, std::equal_to<>> template_map_t;
static template_map_t sStringTemplates;
static template_map_t sDefaultStringTemplates;
static LLStringUtil::format_map_t sDefaultArgs;
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 38d5720556..0056e73cce 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -65,7 +65,6 @@
// for XUIParse
#include "llquaternion.h"
-#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/finder.hpp>
@@ -157,6 +156,7 @@ mWindow(NULL), // set later in startup
mRootView(NULL),
mHelpImpl(NULL)
{
+ LL_PROFILE_ZONE_SCOPED;
LLRender2D::createInstance(image_provider);
LLSpellChecker::createInstance();
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 2ef64baaf6..091e0ab1cf 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -114,7 +114,7 @@ class LLUI : public LLSimpleton<LLUI>
{
LOG_CLASS(LLUI);
public:
- typedef std::map<std::string, LLControlGroup*, std::less<> > settings_map_t;
+ typedef std::unordered_map<std::string, LLControlGroup*, ll::string_hash, std::equal_to<>> settings_map_t;
LLUI(const settings_map_t &settings,
LLImageProviderInterface* image_provider,
diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp
index cd062b23b8..90ba6f1ecc 100644
--- a/indra/llui/lluicolortable.cpp
+++ b/indra/llui/lluicolortable.cpp
@@ -198,8 +198,8 @@ LLUIColor LLUIColorTable::getColor(std::string_view name, const LLColor4& defaul
// update user color, loaded colors are parsed on initialization
void LLUIColorTable::setColor(std::string_view name, const LLColor4& color)
{
- auto it = mUserSetColors.lower_bound(name);
- if(it != mUserSetColors.end() && !(mUserSetColors.key_comp()(name, it->first)))
+ auto it = mUserSetColors.find(name);
+ if(it != mUserSetColors.end())
{
it->second = color;
}
@@ -330,9 +330,8 @@ void LLUIColorTable::clearTable(string_color_map_t& table)
// if the color already exists it changes the color
void LLUIColorTable::setColor(std::string_view name, const LLColor4& color, string_color_map_t& table)
{
- string_color_map_t::iterator it = table.lower_bound(name);
- if(it != table.end()
- && !(table.key_comp()(name, it->first)))
+ string_color_map_t::iterator it = table.find(name);
+ if(it != table.end())
{
it->second = color;
}
diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h
index 0c6286e5eb..aff6f59db6 100644
--- a/indra/llui/lluicolortable.h
+++ b/indra/llui/lluicolortable.h
@@ -27,7 +27,7 @@
#ifndef LL_LLUICOLORTABLE_H_
#define LL_LLUICOLORTABLE_H_
-#include <map>
+#include <unordered_map>
#include "llinitparam.h"
#include "llsingleton.h"
@@ -42,7 +42,7 @@ class LLUIColorTable : public LLSingleton<LLUIColorTable>
LOG_CLASS(LLUIColorTable);
// consider using sorted vector, can be much faster
- typedef std::map<std::string, LLUIColor, std::less<>> string_color_map_t;
+ typedef std::unordered_map<std::string, LLUIColor, ll::string_hash, std::equal_to<>> string_color_map_t;
public:
struct ColorParams : LLInitParam::ChoiceBlock<ColorParams>
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 9abccfd9a0..33ffc3dfc6 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -253,7 +253,7 @@ const LLInitParam::BaseBlock& get_empty_param_block()
// adds a widget and its param block to various registries
//static
-void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& name)
+void LLUICtrlFactory::registerWidget(std::type_index widget_type, std::type_index param_block_type, const std::string& name)
{
// associate parameter block type with template .xml file
std::string* existing_name = LLWidgetNameRegistry::instance().getValue(param_block_type);
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index fc069c078f..f44b4ba4dc 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -65,7 +65,7 @@ class LLDefaultChildRegistry : public LLChildRegistry<LLDefaultChildRegistry>
// lookup widget name by type
class LLWidgetNameRegistry
-: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry>
+: public LLRegistrySingleton<std::type_index, std::string, LLWidgetNameRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLWidgetNameRegistry);
};
@@ -74,7 +74,7 @@ class LLWidgetNameRegistry
// this is used for schema generation
//typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
//class LLDefaultParamBlockRegistry
-//: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry>
+//: public LLRegistrySingleton<std::type_index, empty_param_block_func_t, LLDefaultParamBlockRegistry>
//{
// LLSINGLETON(LLDefaultParamBlockRegistry);
//};
@@ -202,7 +202,7 @@ private:
static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
// helper function for adding widget type info to various registries
- static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag);
+ static void registerWidget(std::type_index widget_type, std::type_index param_block_type, const std::string& tag);
static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
@@ -290,7 +290,7 @@ template <typename PARAM_BLOCK, int DUMMY>
LLUICtrlFactory::ParamDefaults<PARAM_BLOCK, DUMMY>::ParamDefaults()
{
// look up template file for this param block...
- const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK));
+ const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(typeid(PARAM_BLOCK));
if (param_block_tag)
{ // ...and if it exists, back fill values using the most specific template first
PARAM_BLOCK params;
@@ -314,12 +314,12 @@ LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreator
: LLChildRegistry<DERIVED>::StaticRegistrar(tag, func == nullptr ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
{
// add this widget to various registries
- LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);
+ LLUICtrlFactory::instance().registerWidget(typeid(T), typeid(typename T::Params), tag);
// since registry_t depends on T, do this in line here
// TODO: uncomment this for schema generation
//typedef typename T::child_registry_t registry_t;
- //LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
+ //LLChildRegistryRegistry::instance().defaultRegistrar().add(typeid(T), registry_t::instance());
}
#endif //LLUICTRLFACTORY_H
diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp
index 9bf2f4220c..f4ef6f79f1 100644
--- a/indra/llui/llxuiparser.cpp
+++ b/indra/llui/llxuiparser.cpp
@@ -602,7 +602,7 @@ void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& p
LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui");
// add includes for all possible children
- const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name);
+ const std::type_index& type = *LLWidgetTypeRegistry::instance().getValue(type_name);
const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type);
// add choices for valid children
@@ -1459,7 +1459,7 @@ void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int
void LLSimpleXUIParser::characterData(const char *s, int len)
{
- mTextContents += std::string(s, len);
+ mTextContents.append(s, len);
}
void LLSimpleXUIParser::startElement(const char *name, const char **atts)
@@ -1480,24 +1480,24 @@ void LLSimpleXUIParser::startElement(const char *name, const char **atts)
mOutputStack.back().second++;
S32 num_tokens_pushed = 0;
- std::string child_name(name);
+ std::string_view child_name(name);
if (mOutputStack.back().second == 1)
{ // root node for this block
- mScope.push_back(child_name);
+ mScope.emplace_back(child_name);
}
else
{ // compound attribute
if (child_name.find(".") == std::string::npos)
{
- mNameStack.push_back(std::make_pair(child_name, true));
+ mNameStack.emplace_back(child_name, true);
num_tokens_pushed++;
- mScope.push_back(child_name);
+ mScope.emplace_back(child_name);
}
else
{
// parse out "dotted" name into individual tokens
- tokenizer name_tokens(child_name, sep);
+ tokenizer name_tokens(std::string(child_name), sep);
tokenizer::iterator name_token_it = name_tokens.begin();
if(name_token_it == name_tokens.end())
@@ -1603,8 +1603,8 @@ bool LLSimpleXUIParser::processText()
LLStringUtil::trim(mTextContents);
if (!mTextContents.empty())
{
- mNameStack.push_back(std::make_pair(std::string("value"), true));
- mCurAttributeValueBegin = mTextContents.c_str();
+ mNameStack.emplace_back("value", true);
+ mCurAttributeValueBegin = std::move(mTextContents);
mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently);
mNameStack.pop_back();
}
@@ -1648,12 +1648,12 @@ bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr)
bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- if (!strcmp(self.mCurAttributeValueBegin, "true"))
+ if (!strcmp(self.mCurAttributeValueBegin.c_str(), "true"))
{
*((bool*)val_ptr) = true;
return true;
}
- else if (!strcmp(self.mCurAttributeValueBegin, "false"))
+ else if (!strcmp(self.mCurAttributeValueBegin.c_str(), "false"))
{
*((bool*)val_ptr) = false;
return true;
@@ -1665,56 +1665,56 @@ bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr)
bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- *((std::string*)val_ptr) = self.mCurAttributeValueBegin;
+ *((std::string*)val_ptr) = std::move(self.mCurAttributeValueBegin);
return true;
}
bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U8*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S8*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U16*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S16*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), uint_p[assign_a(*(U32*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), int_p[assign_a(*(S32*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(*(F32*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr)
{
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
- return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full;
+ return parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(*(F64*)val_ptr)]).full;
}
bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr)
@@ -1722,7 +1722,7 @@ bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr)
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
LLColor4 value;
- if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
+ if (parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
{
*(LLColor4*)(val_ptr) = value;
return true;
@@ -1736,7 +1736,7 @@ bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr)
LLColor4 value;
LLUIColor* colorp = (LLUIColor*)val_ptr;
- if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
+ if (parse(self.mCurAttributeValueBegin.c_str(), real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full)
{
colorp->set(value);
return true;
@@ -1749,7 +1749,7 @@ bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr)
LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser);
LLUUID temp_id;
// LLUUID::set is destructive, so use temporary value
- if (temp_id.set(std::string(self.mCurAttributeValueBegin)))
+ if (temp_id.set(self.mCurAttributeValueBegin))
{
*(LLUUID*)(val_ptr) = temp_id;
return true;
diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h
index 2179ae54d3..3cc564772e 100644
--- a/indra/llui/llxuiparser.h
+++ b/indra/llui/llxuiparser.h
@@ -40,7 +40,7 @@ class LLView;
// lookup widget type by name
class LLWidgetTypeRegistry
-: public LLRegistrySingleton<std::string, const std::type_info*, LLWidgetTypeRegistry>
+: public LLRegistrySingleton<std::string, std::type_index, LLWidgetTypeRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLWidgetTypeRegistry);
};
@@ -52,7 +52,7 @@ typedef std::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr o
typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t;
class LLChildRegistryRegistry
-: public LLRegistrySingleton<const std::type_info*, widget_registry_t, LLChildRegistryRegistry>
+: public LLRegistrySingleton<std::type_index, widget_registry_t, LLChildRegistryRegistry>
{
LLSINGLETON_EMPTY_CTOR(LLChildRegistryRegistry);
};
@@ -247,7 +247,7 @@ private:
S32 mCurReadDepth;
std::string mCurFileName;
std::string mTextContents;
- const char* mCurAttributeValueBegin;
+ std::string mCurAttributeValueBegin;
std::vector<S32> mTokenSizeStack;
std::vector<std::string> mScope;
std::vector<bool> mEmptyLeafNode;
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index d08d4afac1..a092787cef 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -55,7 +55,7 @@ class LLKeyboard
{
public:
#ifdef LL_SDL_WINDOW
- // linux relies on SDL2 which uses U32 for its native key type
+ // linux relies on SDL which uses U32 for its native key type
typedef U32 NATIVE_KEY_TYPE;
#else
// on non-linux platforms we can get by with a smaller native key type
diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp
index 803a5b8c23..e4d096e2e9 100644
--- a/indra/llwindow/llkeyboardsdl.cpp
+++ b/indra/llwindow/llkeyboardsdl.cpp
@@ -494,164 +494,164 @@ enum class WindowsVK : U32
LL_VK_OEM_CLEAR = 0xFE,
};
-std::map< U32, U32 > mSDL2_to_Win;
+std::map< U32, U32 > mSDL_to_Win;
-U32 LLKeyboardSDL::mapSDL2toWin( U32 aSymbol )
+U32 LLKeyboardSDL::mapSDLtoWin( U32 aSymbol )
{
// <FS:ND> Map SDLK_ virtual keys to Windows LL_VK_ virtual keys.
// Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into LL_VK_ values as those match already.
- if( mSDL2_to_Win.empty() )
+ if( mSDL_to_Win.empty() )
{
- mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK;
- mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB;
- mSDL2_to_Win[ 12 ] = (U32)WindowsVK::LL_VK_CLEAR;
- mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN;
- mSDL2_to_Win[ 19 ] = (U32)WindowsVK::LL_VK_PAUSE;
- mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE;
- mSDL2_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::LL_VK_SPACE;
- mSDL2_to_Win[ SDLK_APOSTROPHE ] = (U32)WindowsVK::LL_VK_OEM_7;
- mSDL2_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::LL_VK_OEM_COMMA;
- mSDL2_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS;
- mSDL2_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::LL_VK_OEM_PERIOD;
- mSDL2_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::LL_VK_OEM_2;
+ mSDL_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK;
+ mSDL_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB;
+ mSDL_to_Win[ 12 ] = (U32)WindowsVK::LL_VK_CLEAR;
+ mSDL_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN;
+ mSDL_to_Win[ 19 ] = (U32)WindowsVK::LL_VK_PAUSE;
+ mSDL_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE;
+ mSDL_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::LL_VK_SPACE;
+ mSDL_to_Win[ SDLK_APOSTROPHE ] = (U32)WindowsVK::LL_VK_OEM_7;
+ mSDL_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::LL_VK_OEM_COMMA;
+ mSDL_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS;
+ mSDL_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::LL_VK_OEM_PERIOD;
+ mSDL_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::LL_VK_OEM_2;
- mSDL2_to_Win[ SDLK_0 ] = (U32)WindowsVK::LL_VK_0;
- mSDL2_to_Win[ SDLK_1 ] = (U32)WindowsVK::LL_VK_1;
- mSDL2_to_Win[ SDLK_2 ] = (U32)WindowsVK::LL_VK_2;
- mSDL2_to_Win[ SDLK_3 ] = (U32)WindowsVK::LL_VK_3;
- mSDL2_to_Win[ SDLK_4 ] = (U32)WindowsVK::LL_VK_4;
- mSDL2_to_Win[ SDLK_5 ] = (U32)WindowsVK::LL_VK_5;
- mSDL2_to_Win[ SDLK_6 ] = (U32)WindowsVK::LL_VK_6;
- mSDL2_to_Win[ SDLK_7 ] = (U32)WindowsVK::LL_VK_7;
- mSDL2_to_Win[ SDLK_8 ] = (U32)WindowsVK::LL_VK_8;
- mSDL2_to_Win[ SDLK_9 ] = (U32)WindowsVK::LL_VK_9;
+ mSDL_to_Win[ SDLK_0 ] = (U32)WindowsVK::LL_VK_0;
+ mSDL_to_Win[ SDLK_1 ] = (U32)WindowsVK::LL_VK_1;
+ mSDL_to_Win[ SDLK_2 ] = (U32)WindowsVK::LL_VK_2;
+ mSDL_to_Win[ SDLK_3 ] = (U32)WindowsVK::LL_VK_3;
+ mSDL_to_Win[ SDLK_4 ] = (U32)WindowsVK::LL_VK_4;
+ mSDL_to_Win[ SDLK_5 ] = (U32)WindowsVK::LL_VK_5;
+ mSDL_to_Win[ SDLK_6 ] = (U32)WindowsVK::LL_VK_6;
+ mSDL_to_Win[ SDLK_7 ] = (U32)WindowsVK::LL_VK_7;
+ mSDL_to_Win[ SDLK_8 ] = (U32)WindowsVK::LL_VK_8;
+ mSDL_to_Win[ SDLK_9 ] = (U32)WindowsVK::LL_VK_9;
- mSDL2_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::LL_VK_OEM_1;
- mSDL2_to_Win[ SDLK_LESS ] = (U32)WindowsVK::LL_VK_OEM_102;
- mSDL2_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS;
- mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS;
+ mSDL_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::LL_VK_OEM_1;
+ mSDL_to_Win[ SDLK_LESS ] = (U32)WindowsVK::LL_VK_OEM_102;
+ mSDL_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS;
+ mSDL_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_OEM_PLUS;
- mSDL2_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_4;
- mSDL2_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::LL_VK_OEM_5;
- mSDL2_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_6;
- mSDL2_to_Win[ SDLK_GRAVE ] = (U32)WindowsVK::LL_VK_OEM_8;
+ mSDL_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_4;
+ mSDL_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::LL_VK_OEM_5;
+ mSDL_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::LL_VK_OEM_6;
+ mSDL_to_Win[ SDLK_GRAVE ] = (U32)WindowsVK::LL_VK_OEM_8;
- mSDL2_to_Win[ SDLK_A ] = (U32)WindowsVK::LL_VK_A;
- mSDL2_to_Win[ SDLK_B ] = (U32)WindowsVK::LL_VK_B;
- mSDL2_to_Win[ SDLK_C ] = (U32)WindowsVK::LL_VK_C;
- mSDL2_to_Win[ SDLK_D ] = (U32)WindowsVK::LL_VK_D;
- mSDL2_to_Win[ SDLK_E ] = (U32)WindowsVK::LL_VK_E;
- mSDL2_to_Win[ SDLK_F ] = (U32)WindowsVK::LL_VK_F;
- mSDL2_to_Win[ SDLK_G ] = (U32)WindowsVK::LL_VK_G;
- mSDL2_to_Win[ SDLK_H ] = (U32)WindowsVK::LL_VK_H;
- mSDL2_to_Win[ SDLK_I ] = (U32)WindowsVK::LL_VK_I;
- mSDL2_to_Win[ SDLK_J ] = (U32)WindowsVK::LL_VK_J;
- mSDL2_to_Win[ SDLK_K ] = (U32)WindowsVK::LL_VK_K;
- mSDL2_to_Win[ SDLK_L ] = (U32)WindowsVK::LL_VK_L;
- mSDL2_to_Win[ SDLK_M ] = (U32)WindowsVK::LL_VK_M;
- mSDL2_to_Win[ SDLK_N ] = (U32)WindowsVK::LL_VK_N;
- mSDL2_to_Win[ SDLK_O ] = (U32)WindowsVK::LL_VK_O;
- mSDL2_to_Win[ SDLK_P ] = (U32)WindowsVK::LL_VK_P;
- mSDL2_to_Win[ SDLK_Q ] = (U32)WindowsVK::LL_VK_Q;
- mSDL2_to_Win[ SDLK_R ] = (U32)WindowsVK::LL_VK_R;
- mSDL2_to_Win[ SDLK_S ] = (U32)WindowsVK::LL_VK_S;
- mSDL2_to_Win[ SDLK_T ] = (U32)WindowsVK::LL_VK_T;
- mSDL2_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_U;
- mSDL2_to_Win[ SDLK_V ] = (U32)WindowsVK::LL_VK_V;
- mSDL2_to_Win[ SDLK_W ] = (U32)WindowsVK::LL_VK_W;
- mSDL2_to_Win[ SDLK_X ] = (U32)WindowsVK::LL_VK_X;
- mSDL2_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_Y;
- mSDL2_to_Win[ SDLK_Z ] = (U32)WindowsVK::LL_VK_Z;
+ mSDL_to_Win[ SDLK_A ] = (U32)WindowsVK::LL_VK_A;
+ mSDL_to_Win[ SDLK_B ] = (U32)WindowsVK::LL_VK_B;
+ mSDL_to_Win[ SDLK_C ] = (U32)WindowsVK::LL_VK_C;
+ mSDL_to_Win[ SDLK_D ] = (U32)WindowsVK::LL_VK_D;
+ mSDL_to_Win[ SDLK_E ] = (U32)WindowsVK::LL_VK_E;
+ mSDL_to_Win[ SDLK_F ] = (U32)WindowsVK::LL_VK_F;
+ mSDL_to_Win[ SDLK_G ] = (U32)WindowsVK::LL_VK_G;
+ mSDL_to_Win[ SDLK_H ] = (U32)WindowsVK::LL_VK_H;
+ mSDL_to_Win[ SDLK_I ] = (U32)WindowsVK::LL_VK_I;
+ mSDL_to_Win[ SDLK_J ] = (U32)WindowsVK::LL_VK_J;
+ mSDL_to_Win[ SDLK_K ] = (U32)WindowsVK::LL_VK_K;
+ mSDL_to_Win[ SDLK_L ] = (U32)WindowsVK::LL_VK_L;
+ mSDL_to_Win[ SDLK_M ] = (U32)WindowsVK::LL_VK_M;
+ mSDL_to_Win[ SDLK_N ] = (U32)WindowsVK::LL_VK_N;
+ mSDL_to_Win[ SDLK_O ] = (U32)WindowsVK::LL_VK_O;
+ mSDL_to_Win[ SDLK_P ] = (U32)WindowsVK::LL_VK_P;
+ mSDL_to_Win[ SDLK_Q ] = (U32)WindowsVK::LL_VK_Q;
+ mSDL_to_Win[ SDLK_R ] = (U32)WindowsVK::LL_VK_R;
+ mSDL_to_Win[ SDLK_S ] = (U32)WindowsVK::LL_VK_S;
+ mSDL_to_Win[ SDLK_T ] = (U32)WindowsVK::LL_VK_T;
+ mSDL_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_U;
+ mSDL_to_Win[ SDLK_V ] = (U32)WindowsVK::LL_VK_V;
+ mSDL_to_Win[ SDLK_W ] = (U32)WindowsVK::LL_VK_W;
+ mSDL_to_Win[ SDLK_X ] = (U32)WindowsVK::LL_VK_X;
+ mSDL_to_Win[ SDLK_Y ] = (U32)WindowsVK::LL_VK_Y;
+ mSDL_to_Win[ SDLK_Z ] = (U32)WindowsVK::LL_VK_Z;
- mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE;
+ mSDL_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE;
- mSDL2_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::LL_VK_NUMLOCK;
- mSDL2_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::LL_VK_SCROLL;
+ mSDL_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::LL_VK_NUMLOCK;
+ mSDL_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::LL_VK_SCROLL;
- mSDL2_to_Win[ SDLK_HELP ] = (U32)WindowsVK::LL_VK_HELP;
- mSDL2_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::LL_VK_SNAPSHOT;
- mSDL2_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::LL_VK_CANCEL;
- mSDL2_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::LL_VK_APPS;
+ mSDL_to_Win[ SDLK_HELP ] = (U32)WindowsVK::LL_VK_HELP;
+ mSDL_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::LL_VK_SNAPSHOT;
+ mSDL_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::LL_VK_CANCEL;
+ mSDL_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::LL_VK_APPS;
- mSDL2_to_Win[ SDLK_UNKNOWN ] = (U32)WindowsVK::LL_VK_UNKNOWN;
- mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK;
- mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB;
- mSDL2_to_Win[ SDLK_CLEAR ] = (U32)WindowsVK::LL_VK_CLEAR;
- mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN;
- mSDL2_to_Win[ SDLK_PAUSE ] = (U32)WindowsVK::LL_VK_PAUSE;
- mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE;
- mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE;
+ mSDL_to_Win[ SDLK_UNKNOWN ] = (U32)WindowsVK::LL_VK_UNKNOWN;
+ mSDL_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::LL_VK_BACK;
+ mSDL_to_Win[ SDLK_TAB ] = (U32)WindowsVK::LL_VK_TAB;
+ mSDL_to_Win[ SDLK_CLEAR ] = (U32)WindowsVK::LL_VK_CLEAR;
+ mSDL_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::LL_VK_RETURN;
+ mSDL_to_Win[ SDLK_PAUSE ] = (U32)WindowsVK::LL_VK_PAUSE;
+ mSDL_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::LL_VK_ESCAPE;
+ mSDL_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::LL_VK_DELETE;
- mSDL2_to_Win[ SDLK_KP_PERIOD ] = (U32)WindowsVK::LL_VK_DELETE; // LL_VK_DECIMAL?
- mSDL2_to_Win[ SDLK_KP_DIVIDE ] = (U32)WindowsVK::LL_VK_DIVIDE;
- mSDL2_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::LL_VK_MULTIPLY;
- mSDL2_to_Win[ SDLK_KP_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS; // LL_VK_SUBSTRACT?
- mSDL2_to_Win[ SDLK_KP_PLUS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; // LL_VK_ADD?
- mSDL2_to_Win[ SDLK_KP_ENTER ] = (U32)WindowsVK::LL_VK_RETURN;
- mSDL2_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::LL_VK_INSERT;
- mSDL2_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::LL_VK_END;
- mSDL2_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::LL_VK_DOWN;
- mSDL2_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::LL_VK_NEXT;
- mSDL2_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::LL_VK_LEFT;
- mSDL2_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::LL_VK_NUMPAD5;
- mSDL2_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::LL_VK_RIGHT;
- mSDL2_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::LL_VK_HOME;
- mSDL2_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::LL_VK_UP;
- mSDL2_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::LL_VK_PRIOR;
+ mSDL_to_Win[ SDLK_KP_PERIOD ] = (U32)WindowsVK::LL_VK_DELETE; // LL_VK_DECIMAL?
+ mSDL_to_Win[ SDLK_KP_DIVIDE ] = (U32)WindowsVK::LL_VK_DIVIDE;
+ mSDL_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::LL_VK_MULTIPLY;
+ mSDL_to_Win[ SDLK_KP_MINUS ] = (U32)WindowsVK::LL_VK_OEM_MINUS; // LL_VK_SUBSTRACT?
+ mSDL_to_Win[ SDLK_KP_PLUS ] = (U32)WindowsVK::LL_VK_OEM_PLUS; // LL_VK_ADD?
+ mSDL_to_Win[ SDLK_KP_ENTER ] = (U32)WindowsVK::LL_VK_RETURN;
+ mSDL_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::LL_VK_INSERT;
+ mSDL_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::LL_VK_END;
+ mSDL_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::LL_VK_DOWN;
+ mSDL_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::LL_VK_NEXT;
+ mSDL_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::LL_VK_LEFT;
+ mSDL_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::LL_VK_NUMPAD5;
+ mSDL_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::LL_VK_RIGHT;
+ mSDL_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::LL_VK_HOME;
+ mSDL_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::LL_VK_UP;
+ mSDL_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::LL_VK_PRIOR;
// ?
- mSDL2_to_Win[ SDLK_UP ] = (U32)WindowsVK::LL_VK_UP;
- mSDL2_to_Win[ SDLK_DOWN ] = (U32)WindowsVK::LL_VK_DOWN;
- mSDL2_to_Win[ SDLK_RIGHT ] = (U32)WindowsVK::LL_VK_RIGHT;
- mSDL2_to_Win[ SDLK_LEFT ] = (U32)WindowsVK::LL_VK_LEFT;
- mSDL2_to_Win[ SDLK_INSERT ] = (U32)WindowsVK::LL_VK_INSERT;
- mSDL2_to_Win[ SDLK_HOME ] = (U32)WindowsVK::LL_VK_HOME;
- mSDL2_to_Win[ SDLK_END ] = (U32)WindowsVK::LL_VK_END;
- mSDL2_to_Win[ SDLK_PAGEUP ] = (U32)WindowsVK::LL_VK_PRIOR;
- mSDL2_to_Win[ SDLK_PAGEDOWN ] = (U32)WindowsVK::LL_VK_NEXT;
- mSDL2_to_Win[ SDLK_F1 ] = (U32)WindowsVK::LL_VK_F1;
- mSDL2_to_Win[ SDLK_F2 ] = (U32)WindowsVK::LL_VK_F2;
- mSDL2_to_Win[ SDLK_F3 ] = (U32)WindowsVK::LL_VK_F3;
- mSDL2_to_Win[ SDLK_F4 ] = (U32)WindowsVK::LL_VK_F4;
- mSDL2_to_Win[ SDLK_F5 ] = (U32)WindowsVK::LL_VK_F5;
- mSDL2_to_Win[ SDLK_F6 ] = (U32)WindowsVK::LL_VK_F6;
- mSDL2_to_Win[ SDLK_F7 ] = (U32)WindowsVK::LL_VK_F7;
- mSDL2_to_Win[ SDLK_F8 ] = (U32)WindowsVK::LL_VK_F8;
- mSDL2_to_Win[ SDLK_F9 ] = (U32)WindowsVK::LL_VK_F9;
- mSDL2_to_Win[ SDLK_F10 ] = (U32)WindowsVK::LL_VK_F10;
- mSDL2_to_Win[ SDLK_F11 ] = (U32)WindowsVK::LL_VK_F11;
- mSDL2_to_Win[ SDLK_F12 ] = (U32)WindowsVK::LL_VK_F12;
- mSDL2_to_Win[ SDLK_F13 ] = (U32)WindowsVK::LL_VK_F13;
- mSDL2_to_Win[ SDLK_F14 ] = (U32)WindowsVK::LL_VK_F14;
- mSDL2_to_Win[ SDLK_F15 ] = (U32)WindowsVK::LL_VK_F15;
- mSDL2_to_Win[ SDLK_CAPSLOCK ] = (U32)WindowsVK::LL_VK_CAPITAL;
- mSDL2_to_Win[ SDLK_RSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT;
- mSDL2_to_Win[ SDLK_LSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT;
- mSDL2_to_Win[ SDLK_RCTRL ] = (U32)WindowsVK::LL_VK_CONTROL;
- mSDL2_to_Win[ SDLK_LCTRL ] = (U32)WindowsVK::LL_VK_CONTROL;
- mSDL2_to_Win[ SDLK_RALT ] = (U32)WindowsVK::LL_VK_MENU;
- mSDL2_to_Win[ SDLK_LALT ] = (U32)WindowsVK::LL_VK_MENU;
+ mSDL_to_Win[ SDLK_UP ] = (U32)WindowsVK::LL_VK_UP;
+ mSDL_to_Win[ SDLK_DOWN ] = (U32)WindowsVK::LL_VK_DOWN;
+ mSDL_to_Win[ SDLK_RIGHT ] = (U32)WindowsVK::LL_VK_RIGHT;
+ mSDL_to_Win[ SDLK_LEFT ] = (U32)WindowsVK::LL_VK_LEFT;
+ mSDL_to_Win[ SDLK_INSERT ] = (U32)WindowsVK::LL_VK_INSERT;
+ mSDL_to_Win[ SDLK_HOME ] = (U32)WindowsVK::LL_VK_HOME;
+ mSDL_to_Win[ SDLK_END ] = (U32)WindowsVK::LL_VK_END;
+ mSDL_to_Win[ SDLK_PAGEUP ] = (U32)WindowsVK::LL_VK_PRIOR;
+ mSDL_to_Win[ SDLK_PAGEDOWN ] = (U32)WindowsVK::LL_VK_NEXT;
+ mSDL_to_Win[ SDLK_F1 ] = (U32)WindowsVK::LL_VK_F1;
+ mSDL_to_Win[ SDLK_F2 ] = (U32)WindowsVK::LL_VK_F2;
+ mSDL_to_Win[ SDLK_F3 ] = (U32)WindowsVK::LL_VK_F3;
+ mSDL_to_Win[ SDLK_F4 ] = (U32)WindowsVK::LL_VK_F4;
+ mSDL_to_Win[ SDLK_F5 ] = (U32)WindowsVK::LL_VK_F5;
+ mSDL_to_Win[ SDLK_F6 ] = (U32)WindowsVK::LL_VK_F6;
+ mSDL_to_Win[ SDLK_F7 ] = (U32)WindowsVK::LL_VK_F7;
+ mSDL_to_Win[ SDLK_F8 ] = (U32)WindowsVK::LL_VK_F8;
+ mSDL_to_Win[ SDLK_F9 ] = (U32)WindowsVK::LL_VK_F9;
+ mSDL_to_Win[ SDLK_F10 ] = (U32)WindowsVK::LL_VK_F10;
+ mSDL_to_Win[ SDLK_F11 ] = (U32)WindowsVK::LL_VK_F11;
+ mSDL_to_Win[ SDLK_F12 ] = (U32)WindowsVK::LL_VK_F12;
+ mSDL_to_Win[ SDLK_F13 ] = (U32)WindowsVK::LL_VK_F13;
+ mSDL_to_Win[ SDLK_F14 ] = (U32)WindowsVK::LL_VK_F14;
+ mSDL_to_Win[ SDLK_F15 ] = (U32)WindowsVK::LL_VK_F15;
+ mSDL_to_Win[ SDLK_CAPSLOCK ] = (U32)WindowsVK::LL_VK_CAPITAL;
+ mSDL_to_Win[ SDLK_RSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT;
+ mSDL_to_Win[ SDLK_LSHIFT ] = (U32)WindowsVK::LL_VK_SHIFT;
+ mSDL_to_Win[ SDLK_RCTRL ] = (U32)WindowsVK::LL_VK_CONTROL;
+ mSDL_to_Win[ SDLK_LCTRL ] = (U32)WindowsVK::LL_VK_CONTROL;
+ mSDL_to_Win[ SDLK_RALT ] = (U32)WindowsVK::LL_VK_MENU;
+ mSDL_to_Win[ SDLK_LALT ] = (U32)WindowsVK::LL_VK_MENU;
- mSDL2_to_Win[ SDLK_MENU ] = (U32)WindowsVK::LL_VK_MENU;
+ mSDL_to_Win[ SDLK_MENU ] = (U32)WindowsVK::LL_VK_MENU;
// LL_VK_MODECHANGE ?
- // mSDL2_to_Win[ SDLK_MODE ] = (U32)WindowsVK::LL_VK_MODE;
+ // mSDL_to_Win[ SDLK_MODE ] = (U32)WindowsVK::LL_VK_MODE;
// ?
- // mSDL2_to_Win[ SDLK_SYSREQ ] = (U32)WindowsVK::LL_VK_SYSREQ;
- // mSDL2_to_Win[ SDLK_POWER ] = (U32)WindowsVK::LL_VK_POWER;
- // mSDL2_to_Win[ SDLK_UNDO ] = (U32)WindowsVK::LL_VK_UNDO;
- // mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_EQUALS;
- // mSDL2_to_Win[ 311 ] = (U32)WindowsVK::LL_VK_LWIN;
- // mSDL2_to_Win[ 312 ] = (U32)WindowsVK::LL_VK_RWIN;
- // mSDL2_to_Win[ SDLK_COLON ] = ?
+ // mSDL_to_Win[ SDLK_SYSREQ ] = (U32)WindowsVK::LL_VK_SYSREQ;
+ // mSDL_to_Win[ SDLK_POWER ] = (U32)WindowsVK::LL_VK_POWER;
+ // mSDL_to_Win[ SDLK_UNDO ] = (U32)WindowsVK::LL_VK_UNDO;
+ // mSDL_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::LL_VK_EQUALS;
+ // mSDL_to_Win[ 311 ] = (U32)WindowsVK::LL_VK_LWIN;
+ // mSDL_to_Win[ 312 ] = (U32)WindowsVK::LL_VK_RWIN;
+ // mSDL_to_Win[ SDLK_COLON ] = ?
}
- auto itr = mSDL2_to_Win.find( aSymbol );
- if( itr != mSDL2_to_Win.end() )
+ auto itr = mSDL_to_Win.find( aSymbol );
+ if( itr != mSDL_to_Win.end() )
return itr->second;
return aSymbol;
diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h
index f23b4cca6c..2ebe647561 100644
--- a/indra/llwindow/llkeyboardsdl.h
+++ b/indra/llwindow/llkeyboardsdl.h
@@ -52,7 +52,7 @@ private:
std::map<KEY, LLKeyboard::NATIVE_KEY_TYPE> mInvTranslateNumpadMap; // inverse of the above
public:
- static U32 mapSDL2toWin( U32 );
+ static U32 mapSDLtoWin( U32 );
};
#endif
diff --git a/indra/llwindow/llsdl.cpp b/indra/llwindow/llsdl.cpp
index 1df9f38a6d..bc38120386 100644
--- a/indra/llwindow/llsdl.cpp
+++ b/indra/llwindow/llsdl.cpp
@@ -1,6 +1,6 @@
/**
* @file llsdl.cpp
- * @brief SDL2 initialization
+ * @brief SDL initialization
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/llwindow/llsdl.h b/indra/llwindow/llsdl.h
index 1a8a12c61c..6c9c9eb07c 100644
--- a/indra/llwindow/llsdl.h
+++ b/indra/llwindow/llsdl.h
@@ -1,6 +1,6 @@
/**
* @file llsdl.h
- * @brief SDL2 initialization
+ * @brief SDL initialization
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp
index 3fc0257a7f..2d8a74c782 100644
--- a/indra/llwindow/llwindowsdl.cpp
+++ b/indra/llwindow/llwindowsdl.cpp
@@ -1815,7 +1815,7 @@ LLSD LLWindowSDL::getNativeKeyData()
// *todo: NUM? - I don't care enough right now (and it's not a GDK modifier).
result["virtual_key"] = (S32)mKeyVirtualKey;
- result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey );
+ result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDLtoWin( mKeyVirtualKey );
result["modifiers"] = (S32)modifiers;
return result;
}
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index 8a95ab2cc2..df6be2546d 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -761,6 +761,7 @@ void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val)
// Returns number of controls loaded, so 0 if failure
U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as)
{
+ LL_PROFILE_ZONE_SCOPED;
std::string name;
LLXmlTree xml_controls;
@@ -995,6 +996,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only
U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values, bool error_when_no_comment)
{
+ LL_PROFILE_ZONE_SCOPED;
LLSD settings;
llifstream infile;
infile.open(filename.c_str());
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index c9bd0a8a32..5aa2b9715e 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -33,8 +33,10 @@
#include "llrect.h"
#include "llrefcount.h"
#include "llinstancetracker.h"
+#include "llstl.h"
#include <functional>
+#include <unordered_map>
#include <vector>
#include <boost/signals2.hpp>
@@ -165,7 +167,7 @@ class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
LOG_CLASS(LLControlGroup);
protected:
- typedef std::map<std::string, LLControlVariablePtr, std::less<> > ctrl_name_table_t;
+ using ctrl_name_table_t = std::unordered_map<std::string, LLControlVariablePtr, ll::string_hash, std::equal_to<>>;
ctrl_name_table_t mNameTable;
static const std::string mTypeString[TYPE_COUNT];
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1d715338cb..4be89df283 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -42,6 +42,7 @@ include(TinyEXR)
include(ThreeJS)
include(Tracy)
include(UI)
+include(Velopack)
include(ViewerMiscLibs)
include(ViewerManager)
include(VisualLeakDetector)
@@ -661,6 +662,7 @@ set(viewer_SOURCE_FILES
llurllineeditorctrl.cpp
llurlwhitelist.cpp
llversioninfo.cpp
+ llvvmquery.cpp
llviewchildren.cpp
llviewerassetstats.cpp
llviewerassetstorage.cpp
@@ -1340,6 +1342,7 @@ set(viewer_HEADER_FILES
llurllineeditorctrl.h
llurlwhitelist.h
llversioninfo.h
+ llvvmquery.h
llviewchildren.h
llviewerassetstats.h
llviewerassetstorage.h
@@ -1452,6 +1455,8 @@ if (DARWIN)
LIST(APPEND viewer_SOURCE_FILES llappviewermacosx-objc.h)
LIST(APPEND viewer_SOURCE_FILES llfilepicker_mac.mm)
LIST(APPEND viewer_HEADER_FILES llfilepicker_mac.h)
+ LIST(APPEND viewer_SOURCE_FILES llvelopack.cpp)
+ LIST(APPEND viewer_HEADER_FILES llvelopack.h)
set_source_files_properties(
llappviewermacosx-objc.mm
@@ -1505,11 +1510,19 @@ if (WINDOWS)
list(APPEND viewer_SOURCE_FILES
llappviewerwin32.cpp
+ llvelopack.cpp
llwindebug.cpp
)
+ set_source_files_properties(
+ llappviewerwin32.cpp
+ llvelopack.cpp
+ PROPERTIES
+ COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
+ )
list(APPEND viewer_HEADER_FILES
llappviewerwin32.h
+ llvelopack.h
llwindebug.h
)
@@ -1929,6 +1942,7 @@ if (WINDOWS)
"--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
+ "--velopack=${USE_VELOPACK}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=$<CONFIG>
"--channel=${VIEWER_CHANNEL}"
@@ -2057,6 +2071,10 @@ if (USE_DISCORD)
target_link_libraries(${VIEWER_BINARY_NAME} ll::discord_sdk )
endif ()
+if (TARGET ll::velopack)
+ target_link_libraries(${VIEWER_BINARY_NAME} ll::velopack )
+endif ()
+
if( TARGET ll::intel_memops )
target_link_libraries(${VIEWER_BINARY_NAME} ll::intel_memops )
endif()
@@ -2253,9 +2271,11 @@ if (DARWIN)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER}
"--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
+ "--velopack=${USE_VELOPACK}"
--build=${CMAKE_CURRENT_BINARY_DIR}
--buildtype=$<CONFIG>
"--channel=${VIEWER_CHANNEL}"
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 2aaedf9944..124b7a2cd0 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-26.1.0
+26.1.1
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 318d2a2883..f7c41873bb 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4237,7 +4237,17 @@
<key>Value</key>
<string>0.0.0</string>
</map>
-
+ <key>PreviousInstallChecked</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether viewer checked previous install on the same channel for NSIS</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>LimitDragDistance</key>
<map>
<key>Comment</key>
@@ -13112,11 +13122,11 @@
<key>UpdaterShowReleaseNotes</key>
<map>
<key>Comment</key>
- <string>Enables displaying of the Release notes in a web floater after update.</string>
+ <string>Enables displaying of the Release notes in a web floater after update. 0 - don't show, 1 - show, 2 - show even for test viewers</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>Boolean</string>
+ <string>S32</string>
<key>Value</key>
<integer>1</integer>
</map>
@@ -16651,16 +16661,27 @@
<key>Value</key>
<integer>2</integer>
</map>
- <key>ScriptEditorDisableSyntaxHighlight</key>
- <map>
- <key>Comment</key>
- <string>Disable syntax highlighting in script editor for performance testing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
+ <key>PurgeDiskCacheOnStartup</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to LRU purge the disk cache during startup on main thread</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ScriptEditorDisableSyntaxHighlight</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable syntax highlighting in script editor for performance testing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
</map>
</llsd>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
index dd9e883fdf..abe61fe892 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
@@ -146,6 +146,9 @@ vec3 srgb_to_linear(vec3 c);
void main()
{
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
+
+ basecolor.a *= vertex_color.a;
+
if (basecolor.a < minimum_alpha)
{
discard;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index e405a9ea2d..69c9e9ff84 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -51,9 +51,7 @@ in vec3 vary_norm;
in vec4 vertex_color; //vertex color should be treated as sRGB
#endif
-#ifdef HAS_ALPHA_MASK
uniform float minimum_alpha;
-#endif
uniform mat4 proj_mat;
uniform mat4 inv_proj;
@@ -225,6 +223,13 @@ void main()
float final_alpha = diffuse_linear.a;
+#ifdef IS_AVATAR_SKIN
+ if(final_alpha < minimum_alpha)
+ {
+ discard;
+ }
+#endif
+
#ifdef USE_VERTEX_COLOR
final_alpha *= vertex_color.a;
diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp
index 187876e3b8..c170672859 100644
--- a/indra/newview/gltf/asset.cpp
+++ b/indra/newview/gltf/asset.cpp
@@ -1027,6 +1027,12 @@ bool Image::prepImpl(Asset& asset, const LLUUID& id)
std::string dir = gDirUtilp->getDirName(asset.mFilename);
std::string img_file = dir + gDirUtilp->getDirDelimiter() + mUri;
+ if (!gDirUtilp->fileExists(img_file))
+ {
+ // URI might be escaped, unescape.
+ img_file = dir + gDirUtilp->getDirDelimiter() + LLURI::unescape(mUri);
+ }
+
LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(img_file);
if (tracking_id.notNull() && mLoadIntoTexturePipe)
{
diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h
index c231443a9e..53dee98cd1 100644
--- a/indra/newview/gltf/buffer_util.h
+++ b/indra/newview/gltf/buffer_util.h
@@ -141,6 +141,42 @@ namespace LL
}
template<>
+ inline void copyScalar<U32, LLVector4a>(U32* src, LLVector4a& dst)
+ {
+ dst.set((F32)*src, 0.f, 0.f, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U16, LLVector4a>(U16* src, LLVector4a& dst)
+ {
+ dst.set((F32)*src, 0.f, 0.f, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U8, LLVector4a>(U8* src, LLVector4a& dst)
+ {
+ dst.set((F32)*src, 0.f, 0.f, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U32, LLVector2>(U32* src, LLVector2& dst)
+ {
+ dst.set((F32)*src, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U16, LLVector2>(U16* src, LLVector2& dst)
+ {
+ dst.set((F32)*src, 0.f);
+ }
+
+ template<>
+ inline void copyScalar<U8, LLVector2>(U8* src, LLVector2& dst)
+ {
+ dst.set((F32)*src, 0.f);
+ }
+
+ template<>
inline void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
{
dst.set(src[0], src[1]);
@@ -221,6 +257,12 @@ namespace LL
}
template<>
+ inline void copyVec4<U32, LLVector4a>(U32* src, LLVector4a& dst)
+ {
+ dst.set((F32)src[0], (F32)src[1], (F32)src[2], (F32)src[3]);
+ }
+
+ template<>
inline void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst)
{
dst.set(src[0], src[1], src[2], src[3]);
@@ -373,7 +415,7 @@ namespace LL
}
else
{
- LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
+ LL_ERRS("GLTF") << "Unsupported accessor type " << (S32)accessor.mType << LL_ENDL;
}
}
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 1af98c3730..66aa29d86b 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -826,7 +826,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const std::string& bas
LL_DEBUGS("GLTF_IMPORT") << "No normals found for primitive, using default normal." << LL_ENDL;
}
- vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], -prim.mTexCoords0[i][1]);
+ // Flip texture V coordinate
+ vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], 1.f - prim.mTexCoords0[i][1]);
if (skinIdx >= 0)
{
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 0e36698018..07ed0d0824 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -767,8 +767,21 @@ Function un.UserSettingsFiles
StrCmp $DO_UNINSTALL_V2 "true" Keep # Don't remove user's settings files on auto upgrade
-# Ask if user wants to keep data files or not
-MessageBox MB_YESNO|MB_ICONQUESTION $(RemoveDataFilesMB) IDYES Remove IDNO Keep
+ClearErrors
+Push $0
+${GetParameters} $COMMANDLINE
+${GetOptionsS} $COMMANDLINE "/clrusrfiles" $0
+# GetOptionsS returns an error if option does not exist, jump past Goto.
+IfErrors +3 0
+ Pop $0
+ Goto Remove
+
+Pop $0
+ClearErrors
+
+ifSilent Keep 0
+ # Ask if user wants to keep data files or not
+ MessageBox MB_YESNO|MB_ICONQUESTION $(RemoveDataFilesMB) IDYES Remove IDNO Keep
Remove:
Push $0
@@ -864,11 +877,25 @@ RMDir "$INSTDIR"
IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER
FOLDERFOUND:
+ifSilent NOFOLDER 0
MessageBox MB_OK $(DeleteProgramFilesMB) /SD IDOK IDOK NOFOLDER
NOFOLDER:
-MessageBox MB_YESNO $(DeleteRegistryKeysMB) IDYES DeleteKeys IDNO NoDelete
+ClearErrors
+Push $0
+${GetParameters} $COMMANDLINE
+${GetOptionsS} $COMMANDLINE "/clearreg" $0
+# GetOptionsS returns an error if option does not exist, jump past Goto.
+IfErrors +3 0
+ Pop $0
+ Goto DeleteKeys
+
+Pop $0
+ClearErrors
+
+ifSilent NoDelete 0
+ MessageBox MB_YESNO $(DeleteRegistryKeysMB) IDYES DeleteKeys IDNO NoDelete
DeleteKeys:
DeleteRegKey SHELL_CONTEXT "SOFTWARE\Classes\x-grid-location-info"
@@ -912,21 +939,7 @@ Function .onInstSuccess
Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
StrCmp $SKIP_AUTORUN "true" +2;
- # Assumes SetOutPath $INSTDIR
- # Run INSTEXE (our updater), passing VIEWER_EXE plus the command-line
- # arguments built into our shortcuts. This gives the updater a chance
- # to verify that the viewer we just installed is appropriate for the
- # running system -- or, if not, to download and install a different
- # viewer. For instance, if a user running 32-bit Windows installs a
- # 64-bit viewer, it cannot run on this system. But since the updater
- # is a 32-bit executable even in the 64-bit viewer package, the
- # updater can detect the problem and adapt accordingly.
- # Once everything is in order, the updater will run the specified
- # viewer with the specified params.
- # Quote the updater executable and the viewer executable because each
- # must be a distinct command-line token, but DO NOT quote the language
- # string because it must decompose into separate command-line tokens.
- Exec '"$INSTDIR\$INSTEXE" precheck "$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
+ Exec '"$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
#
FunctionEnd
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 0d7ad0a124..60af0cad05 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4850,6 +4850,8 @@ const std::string& LLAgent::getTeleportStateName() const
void LLAgent::parseTeleportMessages(const std::string& xml_filename)
{
+ LL_PROFILE_ZONE_SCOPED;
+
LLXMLNodePtr root;
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index f3265afebd..ece18fb5cc 100644
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -144,6 +144,8 @@ LLAppCoreHttp::~LLAppCoreHttp()
void LLAppCoreHttp::init()
{
+ LL_PROFILE_ZONE_SCOPED;
+
LLCoreHttpUtil::setPropertyMethods(
std::bind(&LLControlGroup::getBOOL, std::ref(gSavedSettings), std::placeholders::_1),
std::bind(&LLControlGroup::declareBOOL, std::ref(gSavedSettings), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, LLControlVariable::PERSIST_NONDFT));
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1da7ce1a58..ec4f69a080 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -98,6 +98,11 @@
#include "llurlmatch.h"
#include "lltextutil.h"
#include "lllogininstance.h"
+#include "llvvmquery.h"
+
+#if LL_VELOPACK
+#include "llvelopack.h"
+#endif
#include "llprogressview.h"
#include "llvocache.h"
#include "lldiskcache.h"
@@ -341,9 +346,6 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
S32 gPendingMetricsUploads = 0;
-
-bool gDisconnected = false;
-
// Used to restore texture state after a mode switch
LLFrameTimer gRestoreGLTimer;
bool gRestoreGL = false;
@@ -380,9 +382,6 @@ const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
static std::string gLaunchFileOnQuit;
-// Used on Win32 for other apps to identify our window (eg, win_setup)
-const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
-
//----------------------------------------------------------------------------
// List of entries from strings.xml to always replace
@@ -657,7 +656,6 @@ LLAppViewer::LLAppViewer()
mPurgeCacheOnExit(false),
mPurgeUserDataOnExit(false),
mSecondInstance(false),
- mUpdaterNotFound(false),
mSavedFinalSnapshot(false),
mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded.
mQuitRequested(false),
@@ -736,6 +734,8 @@ public:
bool LLAppViewer::init()
{
+ LL_PROFILE_ZONE_SCOPED;
+
setupErrorHandling(mSecondInstance);
//
@@ -937,6 +937,7 @@ bool LLAppViewer::init()
// Early out from user choice.
LL_WARNS("InitInfo") << "initHardwareTest() failed." << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ;
@@ -955,6 +956,7 @@ bool LLAppViewer::init()
OSMessageBox(msg.c_str(), LLStringUtil::null, OSMB_OK);
LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
@@ -990,6 +992,7 @@ bool LLAppViewer::init()
// Already handled with a MBVideoDrvErr
LL_WARNS("InitInfo") << "gGLManager.mHasRequirements is false." << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
@@ -1003,6 +1006,7 @@ bool LLAppViewer::init()
OSMessageBox(msg.c_str(), LLStringUtil::null, OSMB_OK);
LL_WARNS("InitInfo") << "SSE2 is not supported" << LL_ENDL;
// quit immediately
+ LL_PROFILER_FRAME_END;
return false;
}
#endif
@@ -1113,69 +1117,17 @@ bool LLAppViewer::init()
gGLActive = false;
-#if LL_RELEASE_FOR_DOWNLOAD && !LL_LINUX
- // Skip updater if this is a non-interactive instance
+//#if LL_RELEASE_FOR_DOWNLOAD
+ // Launch VVM update check
if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive)
{
- LLProcess::Params updater;
- updater.desc = "updater process";
- // Because it's the updater, it MUST persist beyond the lifespan of the
- // viewer itself.
- updater.autokill = false;
- std::string updater_file;
-#if LL_WINDOWS
- updater_file = "SLVersionChecker.exe";
- updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file);
-#elif LL_DARWIN
- updater_file = "SLVersionChecker";
- updater.executable = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", updater_file);
-#else
- updater_file = "SLVersionChecker";
- updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file);
-#endif
- // add LEAP mode command-line argument to whichever of these we selected
- updater.args.add("leap");
- // UpdaterServiceSettings
- if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
- {
- // Befor first login, treat this as 'manual' updates,
- // updater won't install anything, but required updates
- updater.args.add("0");
- }
- else
- {
- updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting")));
- }
- // channel
- updater.args.add(LLVersionInfo::instance().getChannel());
- // testok
- updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest")));
- // ForceAddressSize
- updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize")));
-
- try
- {
- // Run the updater. An exception from launching the updater should bother us.
- LLLeap::create(updater, true);
- mUpdaterNotFound = false;
- }
- catch (...)
- {
- LLUIString details = LLNotifications::instance().getGlobalString("LLLeapUpdaterFailure");
- details.setArg("[UPDATER_APP]", updater_file);
- OSMessageBox(
- details.getString(),
- LLStringUtil::null,
- OSMB_OK);
- mUpdaterNotFound = true;
- }
+ initVVMUpdateCheck();
}
else
-#endif //LL_RELEASE_FOR_DOWNLOAD
{
- mUpdaterNotFound = true;
LL_WARNS("InitInfo") << "Skipping updater check." << LL_ENDL;
}
+//#endif //LL_RELEASE_FOR_DOWNLOAD
{
// Iterate over --leap command-line options. But this is a bit tricky: if
@@ -1274,7 +1226,7 @@ bool LLAppViewer::init()
gDirUtilp->deleteDirAndContents(gDirUtilp->getDumpLogsDirPath());
}
#endif
-
+ LL_PROFILER_FRAME_END;
return true;
}
@@ -1711,6 +1663,16 @@ void LLAppViewer::flushLFSIO()
bool LLAppViewer::cleanup()
{
+#if LL_VELOPACK
+ // Apply any pending Velopack update before shutdown
+ if (velopack_is_update_pending())
+ {
+ LL_INFOS("AppInit") << "Applying pending Velopack update on shutdown..." << LL_ENDL;
+ velopack_apply_pending_update(velopack_should_restart_after_update());
+ }
+ velopack_cleanup();
+#endif
+
//ditch LLVOAvatarSelf instance
gAgentAvatarp = NULL;
@@ -2201,6 +2163,8 @@ void LLAppViewer::initGeneralThread()
bool LLAppViewer::initThreads()
{
+ LL_PROFILE_ZONE_SCOPED;
+
static const bool enable_threads = true;
LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange"));
@@ -3048,6 +3012,8 @@ bool LLAppViewer::initConfiguration()
// keeps growing, necessitating a method all its own.
void LLAppViewer::initStrings()
{
+ LL_PROFILE_ZONE_SCOPED;
+
std::string strings_file = "strings.xml";
std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file);
if (strings_path_full.empty() || !LLFile::isfile(strings_path_full))
@@ -3135,6 +3101,7 @@ void LLAppViewer::sendOutOfDiskSpaceNotification()
bool LLAppViewer::initWindow()
{
+ LL_PROFILE_ZONE_SCOPED;
LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
// store setting in a global for easy access and modification
@@ -3146,7 +3113,7 @@ bool LLAppViewer::initWindow()
LLViewerWindow::Params window_params;
window_params
.title(gWindowTitle)
- .name(VIEWER_WINDOW_CLASSNAME)
+ .name(sWindowClass)
.x(gSavedSettings.getS32("WindowX"))
.y(gSavedSettings.getS32("WindowY"))
.width(gSavedSettings.getU32("WindowWidth"))
@@ -3271,16 +3238,6 @@ bool LLAppViewer::initWindow()
return true;
}
-bool LLAppViewer::isUpdaterMissing()
-{
- return mUpdaterNotFound;
-}
-
-bool LLAppViewer::waitForUpdater()
-{
- return !gSavedSettings.getBOOL("CmdLineSkipUpdater") && !mUpdaterNotFound && !gNonInteractive;
-}
-
void LLAppViewer::writeDebugInfo(bool isStatic)
{
#if LL_WINDOWS && LL_BUGSPLAT
@@ -4368,6 +4325,7 @@ U32 LLAppViewer::getObjectCacheVersion()
bool LLAppViewer::initCache()
{
+ LL_PROFILE_ZONE_SCOPED;
mPurgeCache = false;
bool read_only = mSecondInstance;
LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
@@ -4461,19 +4419,22 @@ bool LLAppViewer::initCache()
if (mPurgeCache)
{
- LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
- purgeCache();
+ LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
+ purgeCache();
// clear the new C++ file system based cache
LLDiskCache::getInstance()->clearCache();
- }
- else
+ }
+ else if (gSavedSettings.getBOOL("PurgeDiskCacheOnStartup"))
{
// purge excessive files from the new file system based cache
LLDiskCache::getInstance()->purge();
}
+
+ // Start disk cache purge thread to
+ // purge excessive files from the file system based cache
+ LLAppViewer::getPurgeDiskCacheThread()->start();
}
- LLAppViewer::getPurgeDiskCacheThread()->start();
LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache"));
@@ -4516,6 +4477,7 @@ void LLAppViewer::loadKeyBindings()
// As per GHI #4498, remove old, stale CEF cache folders from previous sessions
void LLAppViewer::purgeCefStaleCaches()
{
+ LL_PROFILE_ZONE_SCOPED;
// TODO: we really shouldn't use a hard coded name for the cache folder here...
const std::string browser_parent_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "cef_cache");
if (LLFile::isdir(browser_parent_cache))
@@ -4723,6 +4685,8 @@ std::string get_name_cache_filename(const std::string &base_file, const std::str
void LLAppViewer::loadNameCache()
{
+ LL_PROFILE_ZONE_SCOPED;
+
// display names cache
std::string filename = get_name_cache_filename("avatar_name_cache", "xml");
LL_INFOS("AvNameCache") << filename << LL_ENDL;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 6b0d3e0b27..c977757e48 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -117,9 +117,6 @@ public:
bool quitRequested() { return mQuitRequested; }
bool logoutRequestSent() { return mLogoutRequestSent; }
bool isSecondInstance() { return mSecondInstance; }
- bool isUpdaterMissing(); // In use by tests
- bool waitForUpdater();
-
void writeDebugInfo(bool isStatic=true);
void setServerReleaseNotesURL(const std::string& url) { mServerReleaseNotesURL = url; }
@@ -287,6 +284,14 @@ protected:
virtual void sendOutOfDiskSpaceNotification();
+protected:
+
+ // NSIS relies on this to detect if viewer is up.
+ // NSIS's method is somewhat unreliable since window
+ // can close long before cleanup is done.
+ // sendURLToOtherInstance also relies on this to detect if viewer is up.
+ static constexpr const char* sWindowClass = "Second Life";
+
private:
bool doFrame();
@@ -327,7 +332,6 @@ private:
static LLAppViewer* sInstance;
bool mSecondInstance; // Is this a second instance of the app?
- bool mUpdaterNotFound; // True when attempt to start updater failed
std::string mMarkerFileName;
LLAPRFile mMarkerFile; // A file created to indicate the app is running.
@@ -417,8 +421,6 @@ extern S32 gPendingMetricsUploads;
extern F32 gSimLastTime;
extern F32 gSimFrames;
-extern bool gDisconnected;
-
extern LLFrameTimer gRestoreGLTimer;
extern bool gRestoreGL;
extern bool gUseWireframe;
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index d6ea462b89..f8ea09d40e 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -74,6 +74,11 @@
#include "llversioninfovars.h"
+// Velopack installer and update framework
+#if LL_VELOPACK
+#include "llvelopack.h"
+#endif
+
// Bugsplat (http://bugsplat.com) crash reporting tool
#ifdef LL_BUGSPLAT
#include "BugSplat.h"
@@ -222,7 +227,6 @@ LONG WINAPI catchallCrashHandler(EXCEPTION_POINTERS * /*ExceptionInfo*/)
return 0;
}
-const std::string LLAppViewerWin32::sWindowClass = "Second Life";
/*
This function is used to print to the command line a text message
@@ -426,6 +430,31 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
PWSTR pCmdLine,
int nCmdShow)
{
+#if LL_VELOPACK
+ // Velopack MUST be initialized first - it may handle install/uninstall
+ // commands and exit the process before we do anything else.
+ if (!velopack_initialize())
+ {
+ // Velopack handled the invocation (install/uninstall hook)
+
+ // Drop install related settings
+ gDirUtilp->initAppDirs("SecondLife");
+
+ std::string user_settings_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "settings.xml");
+ LLControlGroup settings("global");
+ if (settings.loadFromFile(user_settings_path))
+ {
+ // If user reinstalls or updates, we want to recheck for nsis leftovers.
+ if (settings.controlExists("PreviousInstallChecked"))
+ {
+ settings.setBOOL("PreviousInstallChecked", false);
+ }
+ settings.saveToFile(user_settings_path, true);
+ }
+ return 0;
+ }
+#endif
+
// Call Tracy first thing to have it allocate memory
// https://github.com/wolfpld/tracy/issues/196
LL_PROFILER_FRAME_END;
@@ -935,7 +964,7 @@ bool LLAppViewerWin32::restoreErrorTrap()
bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
{
wchar_t window_class[256]; /* Flawfinder: ignore */ // Assume max length < 255 chars.
- mbstowcs(window_class, sWindowClass.c_str(), 255);
+ mbstowcs(window_class, sWindowClass, 255);
window_class[255] = 0;
// Use the class instead of the window name.
HWND other_window = FindWindow(window_class, NULL);
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index 3fad53ec72..0741758a0c 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -59,8 +59,6 @@ protected:
std::string generateSerialNumber();
- static const std::string sWindowClass;
-
private:
void disableWinErrorReporting();
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 80c7f8beca..de3ce901c1 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -47,7 +47,7 @@ S32 LLAvatarListItem::sLeftPadding = 0;
S32 LLAvatarListItem::sNameRightPadding = 0;
S32 LLAvatarListItem::sChildrenWidths[LLAvatarListItem::ALIC_COUNT];
-static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(&typeid(LLAvatarListItem::Params), "avatar_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterAvatarListItemParams(typeid(LLAvatarListItem::Params), "avatar_list_item");
LLAvatarListItem::Params::Params()
: default_style("default_style"),
diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp
index 76e308a966..2c9d74ed97 100644
--- a/indra/newview/llcallingcard.cpp
+++ b/indra/newview/llcallingcard.cpp
@@ -680,6 +680,8 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)
LLNotifications::instance().add("RevokedModifyRights",args, payload);
}
}
+ // update modify permissions flags for affected objects
+ LLViewerObject::markObjectsForUpdate(agent_id);
(mBuddyInfo[agent_id])->setRightsFrom(new_rights);
}
}
diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h
index 484bd2ef04..acc752588d 100644
--- a/indra/newview/llcapabilityprovider.h
+++ b/indra/newview/llcapabilityprovider.h
@@ -37,12 +37,12 @@
class LLCapabilityProvider
{
public:
- virtual ~LLCapabilityProvider() {}
+ virtual ~LLCapabilityProvider() = default;
/**
* Get a capability URL, given a capability name. Returns empty string if
* no such capability is defined on this provider.
*/
- virtual std::string getCapability(const std::string& name) const = 0;
+ virtual std::string getCapability(std::string_view name) const = 0;
/**
* Get host to which to send that capability request.
*/
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 20b99393fd..c5af3bec9e 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -210,7 +210,8 @@ namespace
filter_vec.push_back({ "RAW files (*.raw)", "raw" });
break;
case LLFilePicker::FFLOAD_MODEL:
- filter_vec.push_back({ "Model files (*.dae)", "dae" });
+ filter_vec.push_back({ "Model files (*.dae; *.gltf; *.glb)", "dae;gltf;glb" });
+ filter_vec.push_back({ "Collada files (*.dae)", "dae" });
filter_vec.push_back({ "GLTF Files (*.gltf; *.glb)", "gltf;glb" });
break;
case LLFilePicker::FFLOAD_MATERIAL:
diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm
index 6921cd6101..7262d18483 100644
--- a/indra/newview/llfilepicker_mac.mm
+++ b/indra/newview/llfilepicker_mac.mm
@@ -241,8 +241,13 @@ void doSaveDialogModeless(const std::string* file,
NSURL* url = [NSURL fileURLWithPath:fileName];
[panel setNameFieldStringValue: fileName];
- [panel setDirectoryURL: url];
+ NSURL *last_url = [[NSUserDefaults standardUserDefaults] URLForKey:@"NSNavLastRootDirectory"];
+ if(!last_url)
+ {
+ NSURL *documents_url = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject;
+ [panel setDirectoryURL:documents_url];
+ }
[panel beginWithCompletionHandler:^(NSModalResponse result)
{
diff --git a/indra/newview/llfloatermarketplace.cpp b/indra/newview/llfloatermarketplace.cpp
index 2a67e75fec..bb2378d864 100644
--- a/indra/newview/llfloatermarketplace.cpp
+++ b/indra/newview/llfloatermarketplace.cpp
@@ -56,6 +56,7 @@ void LLFloaterMarketplace::onOpen(const LLSD& key)
else
{
openMarketplaceURL(params.url);
+ set_current_url(params.url); // Fix looping back to previous url when using the viewer navigation bar
}
}
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index ac8477a615..b784419780 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -170,7 +170,7 @@ namespace
void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::string& data_in)
{
- std::istringstream str(data_in);
+ boost::iostreams::stream<boost::iostreams::array_source> str(data_in.data(), data_in.size());
LLSD data;
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index a435a4f7c7..aa6ba6d023 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -41,7 +41,7 @@
#include "llinventorymodel.h"
#include "llviewerinventory.h"
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelInventoryListItemBaseParams(&typeid(LLPanelInventoryListItemBase::Params), "inventory_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelInventoryListItemBaseParams(typeid(LLPanelInventoryListItemBase::Params), "inventory_list_item");
constexpr S32 WIDGET_SPACING = 3;
constexpr S32 FAVORITE_IMAGE_SIZE = 14;
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 01ff01e233..870f0873b9 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -3425,6 +3425,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
LLSD inventory;
if (!is_cache_obsolete)
{
+ LL_PROFILE_ZONE_NAMED("inventory load from file - llsd parse");
LLPointer<LLSDParser> parser = new LLSDBinaryParser();
if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
@@ -3436,56 +3437,61 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
if (!is_cache_obsolete)
{
- const LLSD& llsd_cats = inventory["categories"];
- if (llsd_cats.isArray())
{
- LLSD::array_const_iterator iter = llsd_cats.beginArray();
- LLSD::array_const_iterator end = llsd_cats.endArray();
- for (; iter != end; ++iter)
+ LL_PROFILE_ZONE_NAMED("inventory load from file - categories");
+ const LLSD& llsd_cats = inventory["categories"];
+ if (llsd_cats.isArray())
{
- LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
- if (inv_cat->importLLSDMap(*iter))
+ LLSD::array_const_iterator iter = llsd_cats.beginArray();
+ LLSD::array_const_iterator end = llsd_cats.endArray();
+ for (; iter != end; ++iter)
{
- categories.push_back(inv_cat);
+ LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
+ if (inv_cat->importLLSDMap(*iter))
+ {
+ categories.push_back(inv_cat);
+ }
}
}
}
- const LLSD& llsd_items = inventory["items"];
- if (llsd_items.isArray())
{
- LLSD::array_const_iterator iter = llsd_items.beginArray();
- LLSD::array_const_iterator end = llsd_items.endArray();
- for (; iter != end; ++iter)
+ LL_PROFILE_ZONE_NAMED("inventory load from file - items");
+ const LLSD& llsd_items = inventory["items"];
+ if (llsd_items.isArray())
{
- LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
- if (inv_item->fromLLSD(*iter))
+ LLSD::array_const_iterator iter = llsd_items.beginArray();
+ LLSD::array_const_iterator end = llsd_items.endArray();
+ for (; iter != end; ++iter)
{
- if (inv_item->getUUID().isNull())
+ LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
+ if (inv_item->fromLLSD(*iter))
{
- LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: "
- << inv_item->getName() << LL_ENDL;
- }
- else
- {
- if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+ if (inv_item->getUUID().isNull())
{
- cats_to_update.insert(inv_item->getParentUUID());
+ LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " << inv_item->getName() << LL_ENDL;
}
else
{
- items.push_back(inv_item);
+ if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+ {
+ cats_to_update.insert(inv_item->getParentUUID());
+ }
+ else
+ {
+ items.push_back(inv_item);
+ }
}
}
- }
- // TODO(brad) - figure out how to reenable this without breaking everything else
- // static constexpr U64 BATCH_SIZE = 512U;
- // if ((++lines_count % BATCH_SIZE) == 0)
- // {
- // // SL-19968 - make sure message system code gets a chance to run every so often
- // pump_idle_startup_network();
- // }
+ // TODO(brad) - figure out how to reenable this without breaking everything else
+ // static constexpr U64 BATCH_SIZE = 512U;
+ // if ((++lines_count % BATCH_SIZE) == 0)
+ // {
+ // // SL-19968 - make sure message system code gets a chance to run every so often
+ // pump_idle_startup_network();
+ // }
+ }
}
}
}
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 9fbabec8f3..05ada9121a 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -201,13 +201,13 @@ private:
// the inventory using several different identifiers.
// mInventory member data is the 'master' list of inventory, and
// mCategoryMap and mItemMap store uuid->object mappings.
- typedef std::map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t;
- typedef std::map<LLUUID, LLPointer<LLViewerInventoryItem> > item_map_t;
+ typedef std::unordered_map<LLUUID, LLPointer<LLViewerInventoryCategory> > cat_map_t;
+ typedef std::unordered_map<LLUUID, LLPointer<LLViewerInventoryItem>> item_map_t;
cat_map_t mCategoryMap;
item_map_t mItemMap;
// This last set of indices is used to map parents to children.
- typedef std::map<LLUUID, cat_array_t*> parent_cat_map_t;
- typedef std::map<LLUUID, item_array_t*> parent_item_map_t;
+ typedef std::unordered_map<LLUUID, cat_array_t*> parent_cat_map_t;
+ typedef std::unordered_map<LLUUID, item_array_t*> parent_item_map_t;
parent_cat_map_t mParentChildCategoryTree;
parent_item_map_t mParentChildItemTree;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 8d57a4e7bb..06dd830416 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -2125,8 +2125,7 @@ LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
{
LL_PROFILE_ZONE_SCOPED;
- std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
- map_it = mItemMap.find(id);
+ auto map_it = mItemMap.find(id);
if (map_it != mItemMap.end())
{
return map_it->second;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index dc2e304ab3..ca2d5814bc 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -300,7 +300,7 @@ protected:
LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge;
Params mParams; // stored copy of parameter block
- std::map<LLUUID, LLFolderViewItem*> mItemMap;
+ std::unordered_map<LLUUID, LLFolderViewItem*> mItemMap;
/**
* Pointer to LLInventoryFolderViewModelBuilder.
*
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index e9d68723d3..0358233637 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -277,11 +277,6 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
mRequestData["params"] = request_params;
mRequestData["options"] = requested_options;
mRequestData["http_params"] = http_params;
-#if LL_RELEASE_FOR_DOWNLOAD
- mRequestData["wait_for_updater"] = LLAppViewer::instance()->waitForUpdater();
-#else
- mRequestData["wait_for_updater"] = false;
-#endif
}
bool LLLoginInstance::handleLoginEvent(const LLSD& event)
@@ -316,13 +311,6 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
// Login has failed.
// Figure out why and respond...
LLSD response = event["data"];
- LLSD updater = response["updater"];
-
- // Always provide a response to the updater, if in fact the updater
- // contacted us, if in fact the ping contains a 'reply' key. Most code
- // paths tell it not to proceed with updating.
- ResponsePtr resp(std::make_shared<LLEventAPI::Response>
- (LLSDMap("update", false), updater));
std::string reason_response = response["reason"].asString();
std::string message_response = response["message"].asString();
@@ -385,26 +373,15 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
}
else if(reason_response == "update")
{
- // This can happen if the user clicked Login quickly, before we heard
- // back from the Viewer Version Manager, but login failed because
- // login.cgi is insisting on a required update. We were called with an
- // event that bundles both the login.cgi 'response' and the
- // synchronization event from the 'updater'.
+ // login.cgi rejected login and requires an update. Since Velopack
+ // handles updates now, the best we can do here is tell the user
+ // to download the update manually via the release notes URL.
std::string login_version = response["message_args"]["VERSION"];
- std::string vvm_version = updater["VERSION"];
- std::string relnotes = updater["URL"];
LL_WARNS("LLLogin") << "Login failed because an update to version " << login_version << " is required." << LL_ENDL;
- // vvm_version might be empty because we might not have gotten
- // SLVersionChecker's LoginSync handshake. But if it IS populated, it
- // should (!) be the same as the version we got from login.cgi.
- if ((! vvm_version.empty()) && vvm_version != login_version)
- {
- LL_WARNS("LLLogin") << "VVM update version " << vvm_version
- << " differs from login version " << login_version
- << "; presenting VVM version to match release notes URL"
- << LL_ENDL;
- login_version = vvm_version;
- }
+
+ // Try to use the release notes URL from the VVM query if available,
+ // otherwise fall back to constructing one from the version.
+ std::string relnotes = LLVersionInfo::instance().getReleaseNotes();
if (relnotes.empty() || relnotes.find("://") == std::string::npos)
{
relnotes = LLTrans::getString("RELEASE_NOTES_BASE_URL");
@@ -420,32 +397,11 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
args["VERSION"] = login_version;
args["URL"] = relnotes;
- if (updater.isUndefined())
- {
- // If the updater failed to shake hands, better advise the user to
- // download the update him/herself.
- LLNotificationsUtil::add(
- "RequiredUpdate",
- args,
- updater,
- boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
- }
- else
- {
- // If we've heard from the updater that an update is required,
- // then display the prompt that assures the user we'll take care
- // of it. This is the one case in which we bind 'resp':
- // instead of destroying our Response object (and thus sending a
- // negative reply to the updater) as soon as we exit this
- // function, bind our shared_ptr so it gets passed into
- // syncWithUpdater. That ensures that the response is delayed
- // until the user has responded to the notification.
- LLNotificationsUtil::add(
- "PauseForUpdate",
- args,
- updater,
- boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2));
- }
+ LLNotificationsUtil::add(
+ "RequiredUpdate",
+ args,
+ LLSD(),
+ boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
}
else if(reason_response == "mfa_challenge")
{
@@ -479,19 +435,6 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
}
}
-void LLLoginInstance::syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response)
-{
- LL_INFOS("LLLogin") << "LLLoginInstance::syncWithUpdater" << LL_ENDL;
- // 'resp' points to an instance of LLEventAPI::Response that will be
- // destroyed as soon as we return and the notification response functor is
- // unregistered. Modify it so that it tells the updater to go ahead and
- // perform the update. Naturally, if we allowed the user a choice as to
- // whether to proceed or not, this assignment would reflect the user's
- // selection.
- (*resp)["update"] = true;
- attemptComplete();
-}
-
void LLLoginInstance::handleLoginDisallowed(const LLSD& notification, const LLSD& response)
{
attemptComplete();
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index 54ce51720f..551ad92d33 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -28,8 +28,6 @@
#define LL_LLLOGININSTANCE_H
#include "lleventdispatcher.h"
-#include "lleventapi.h"
-#include <memory> // std::shared_ptr
#include "llsecapi.h"
class LLLogin;
class LLEventStream;
@@ -72,10 +70,7 @@ public:
void saveMFAHash(LLSD const& response);
private:
- typedef std::shared_ptr<LLEventAPI::Response> ResponsePtr;
void constructAuthParams(LLPointer<LLCredential> user_credentials);
- void updateApp(bool mandatory, const std::string& message);
- bool updateDialogCallback(const LLSD& notification, const LLSD& response);
bool handleLoginEvent(const LLSD& event);
void handleLoginFailure(const LLSD& event);
@@ -83,7 +78,6 @@ private:
void handleDisconnect(const LLSD& event);
void handleIndeterminate(const LLSD& event);
void handleLoginDisallowed(const LLSD& notification, const LLSD& response);
- void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
bool handleTOSResponse(bool v, const std::string& key);
void showMFAChallange(const std::string& message);
diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp
index 51c38aba3a..0a90cf0699 100644
--- a/indra/newview/llmachineid.cpp
+++ b/indra/newview/llmachineid.cpp
@@ -398,6 +398,8 @@ bool getSerialNumber(unsigned char *unique_id, size_t len)
S32 LLMachineID::init()
{
+ LL_PROFILE_ZONE_SCOPED;
+
size_t len = sizeof(static_unique_id);
memset(static_unique_id, 0, len);
S32 ret_code = 0;
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
index ac4c18d60c..5fc0b1b290 100644
--- a/indra/newview/llmaterialmgr.h
+++ b/indra/newview/llmaterialmgr.h
@@ -33,9 +33,42 @@
#include "httprequest.h"
#include "httpheaders.h"
#include "httpoptions.h"
+#include <boost/container_hash/hash.hpp>
class LLViewerRegion;
+// struct for TE-specific material ID query
+class TEMaterialPair
+{
+public:
+ U32 te;
+ LLMaterialID materialID;
+
+ bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
+};
+
+inline bool operator<(const TEMaterialPair& lhs, const TEMaterialPair& rhs)
+{
+ return (lhs.te < rhs.te) ? true : (lhs.materialID < rhs.materialID);
+}
+
+// std::hash implementation for TEMaterialPair
+namespace std
+{
+ template<>
+ struct hash<TEMaterialPair>
+ {
+ inline size_t operator()(const TEMaterialPair& p) const noexcept
+ {
+ // Utilize boost::hash_combine to generate a good hash
+ size_t seed = 0;
+ boost::hash_combine(seed, p.te + 1);
+ boost::hash_combine(seed, p.materialID);
+ return seed;
+ }
+ };
+} // namespace std
+
class LLMaterialMgr : public LLSingleton<LLMaterialMgr>
{
LLSINGLETON(LLMaterialMgr);
@@ -83,29 +116,6 @@ private:
void onRegionRemoved(LLViewerRegion* regionp);
private:
- // struct for TE-specific material ID query
- class TEMaterialPair
- {
- public:
-
- U32 te;
- LLMaterialID materialID;
-
- bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
- };
-
- // definitions follow class
- friend std::hash<TEMaterialPair>;
- friend size_t hash_value(const TEMaterialPair&) noexcept;
-
- friend inline bool operator<(
- const LLMaterialMgr::TEMaterialPair& lhs,
- const LLMaterialMgr::TEMaterialPair& rhs)
- {
- return (lhs.te < rhs.te) ? true :
- (lhs.materialID < rhs.materialID);
- }
-
typedef std::set<LLMaterialID> material_queue_t;
typedef std::map<LLUUID, material_queue_t> get_queue_t;
typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
@@ -113,7 +123,7 @@ private:
typedef std::map<LLMaterialID, std::unique_ptr<get_callback_t>> get_callback_map_t;
- typedef boost::unordered_map<TEMaterialPair, std::unique_ptr<get_callback_te_t>> get_callback_te_map_t;
+ typedef std::unordered_map<TEMaterialPair, std::unique_ptr<get_callback_te_t>> get_callback_te_map_t;
typedef std::set<LLUUID> getall_queue_t;
typedef std::map<LLUUID, F64> getall_pending_map_t;
typedef std::map<LLUUID, std::unique_ptr<getall_callback_t>> getall_callback_map_t;
@@ -142,23 +152,5 @@ private:
U32 getMaxEntries(const LLViewerRegion* regionp);
};
-// std::hash implementation for TEMaterialPair
-namespace std
-{
- template<> struct hash<LLMaterialMgr::TEMaterialPair>
- {
- inline size_t operator()(const LLMaterialMgr::TEMaterialPair& p) const noexcept
- {
- return size_t((p.te + 1) * p.materialID.getDigest64());
- }
- };
-}
-
-// For use with boost containers.
-inline size_t hash_value(const LLMaterialMgr::TEMaterialPair& p) noexcept
-{
- return size_t((p.te + 1) * p.materialID.getDigest64());
-}
-
#endif // LL_LLMATERIALMGR_H
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 56ad8297c7..061b4b5428 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -442,7 +442,7 @@ public:
LLCondition* mSignal;
//map of known mesh headers
- typedef boost::unordered_map<LLUUID, LLMeshHeader> mesh_header_map; // pair is header_size and data
+ typedef std::unordered_map<LLUUID, LLMeshHeader> mesh_header_map; // pair is header_size and data
mesh_header_map mMeshHeader;
class HeaderRequest : public RequestStats
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index ed5ab35439..bc9ca46672 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -3461,7 +3461,7 @@ bool LLModelPreview::render()
LLViewerCamera::getInstance()->setAspect(aspect);
- LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
+ LLViewerCamera::getInstance()->setViewNoBroadcast(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
LLVector3 offset = mCameraOffset;
LLVector3 target_pos = mPreviewTarget + offset;
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index ea874e104b..c0a2bb5e51 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -582,6 +582,8 @@ std::vector<LLMute> LLMuteList::getMutes() const
//-----------------------------------------------------------------------------
bool LLMuteList::loadFromFile(const std::string& filename)
{
+ LL_PROFILE_ZONE_SCOPED;
+
if(!filename.size())
{
LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL;
@@ -966,6 +968,8 @@ bool LLRenderMuteList::saveToFile()
bool LLRenderMuteList::loadFromFile()
{
+ LL_PROFILE_ZONE_SCOPED;
+
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt");
LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb"));
if (!fp)
diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp
index 8a070babcd..9b21a217db 100644
--- a/indra/newview/lloutfitgallery.cpp
+++ b/indra/newview/lloutfitgallery.cpp
@@ -850,7 +850,12 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id)
// Start observing changes in "My Outfits" category.
mCategoriesObserver->addCategory(cat_id,
- boost::bind(&LLOutfitGallery::refreshOutfit, this, cat_id), true);
+ [this, cat_id]()
+ {
+ mPendingOutfitRefreshes.insert(cat_id);
+ startIdleLoop(cat_id);
+ },
+ true);
outfit_category->fetch();
refreshOutfit(cat_id);
@@ -901,6 +906,18 @@ void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat,
}
}
+bool LLOutfitGallery::updateOneOutfit()
+{
+ if (mPendingOutfitRefreshes.empty())
+ return false;
+
+ auto it = mPendingOutfitRefreshes.begin();
+ LLUUID outfit_id = *it;
+ mPendingOutfitRefreshes.erase(it);
+ refreshOutfit(outfit_id);
+ return true;
+}
+
void LLOutfitGallery::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id)
{
if (mOutfitMenu && cat_id.notNull())
diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h
index 5801a32a39..183b6ea9d5 100644
--- a/indra/newview/lloutfitgallery.h
+++ b/indra/newview/lloutfitgallery.h
@@ -98,6 +98,7 @@ public:
/*virtual*/ void updateAddedCategory(LLUUID cat_id);
/*virtual*/ void updateRemovedCategory(LLUUID cat_id);
/*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name);
+ /*virtual*/ bool updateOneOutfit(); // bulk processing, scheduled by observer when updates are needed
/*virtual*/ bool hasItemSelected();
/*virtual*/ bool canWearSelected();
@@ -190,6 +191,7 @@ private:
typedef item_num_map_t::value_type item_numb_map_value_t;
item_num_map_t mItemIndexMap;
std::map<S32, LLOutfitGalleryItem*> mIndexToItemMap;
+ std::set<LLUUID> mPendingOutfitRefreshes;
LLInventoryCategoriesObserver* mOutfitsObserver;
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 32831fcd9b..7db79c7010 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -1055,6 +1055,15 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id)
}
}
+void LLOutfitListBase::startIdleLoop(const LLUUID cat_id)
+{
+ if (mRefreshListState.CategoryUUID.isNull())
+ {
+ mRefreshListState.CategoryUUID = cat_id;
+ gIdleCallbacks.addFunction(onIdle, this);
+ }
+}
+
// static
void LLOutfitListBase::onIdle(void* userdata)
{
@@ -1129,6 +1138,14 @@ void LLOutfitListBase::onIdleRefreshList()
return;
}
+ // Let derived classes process their own updates.
+ while (updateOneOutfit())
+ {
+ curent_time = LLTimer::getTotalSeconds();
+ if (curent_time >= end_time)
+ return;
+ }
+
sortOutfits();
highlightBaseOutfit();
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index bcf7e45696..408ff07116 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -95,6 +95,17 @@ public:
virtual void updateAddedCategory(LLUUID cat_id) = 0;
virtual void updateRemovedCategory(LLUUID cat_id) = 0;
virtual void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) = 0;
+
+ /*
+ * Optional hook for derived classes to perform additional processing.
+ * This is called by the outfit list update logic after the core
+ * bookkeeping for an outfit has been handled.
+ *
+ * @return true if update processing should continue,
+ * false if no additional work is required.
+ * The base implementation returns false.
+ */
+ virtual bool updateOneOutfit() { return false; };
virtual void sortOutfits();
void removeSelected();
@@ -138,6 +149,7 @@ protected:
bool isOutfitFolder(LLViewerInventoryCategory* cat) const;
+ void startIdleLoop(const LLUUID cat_id);
static void onIdle(void* userdata);
void onIdleRefreshList();
@@ -150,6 +162,7 @@ protected:
uuid_vec_t::const_iterator RemovedIterator;
} mRefreshListState;
std::set<LLUUID> mChangedItems;
+ std::set<LLUUID> mPendingOutfitRefreshes;
bool mIsInitialized;
LLInventoryCategoriesObserver* mCategoriesObserver;
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index ae010b2259..3bb416afd7 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -37,6 +37,9 @@
#include "llappviewer.h"
#include "llbutton.h"
+#if LL_VELOPACK
+#include "llvelopack.h"
+#endif
#include "llcheckboxctrl.h"
#include "llcommandhandler.h" // for secondlife:///app/login/
#include "llcombobox.h"
@@ -940,6 +943,19 @@ void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
// static
void LLPanelLogin::onClickConnect(bool commit_fields)
{
+#if LL_VELOPACK
+ // In theory, you should never be able to get here.
+ // If there's a required update, try as you might you're not supposed to actually close the downloading update dialog.
+ // But just in case...
+ if (velopack_is_required_update_in_progress())
+ {
+ LLSD args;
+ args["VERSION"] = velopack_get_required_update_version();
+ LLNotificationsUtil::add("DownloadingUpdate", args);
+ return;
+ }
+#endif
+
if (sInstance && sInstance->mCallback && !sInstance->mAlertNotif)
{
if (commit_fields)
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index a31a54bb67..d27ce81e4f 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -1830,7 +1830,7 @@ void LLPanelObjectInventory::onFocusReceived()
LLFolderViewItem* LLPanelObjectInventory::getItemByID( const LLUUID& id )
{
- std::map<LLUUID, LLFolderViewItem*>::iterator map_it = mItemMap.find(id);
+ auto map_it = mItemMap.find(id);
if (map_it != mItemMap.end())
{
return map_it->second;
diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h
index 154639e4bb..13e27b489c 100644
--- a/indra/newview/llpanelobjectinventory.h
+++ b/indra/newview/llpanelobjectinventory.h
@@ -109,7 +109,7 @@ protected:
bool isSelectionRemovable();
private:
- std::map<LLUUID, LLFolderViewItem*> mItemMap;
+ std::unordered_map<LLUUID, LLFolderViewItem*> mItemMap;
LLScrollContainer* mScroller;
LLFolderView* mFolders;
diff --git a/indra/newview/llperfstats.h b/indra/newview/llperfstats.h
index 1a2098ec7e..38deb87237 100644
--- a/indra/newview/llperfstats.h
+++ b/indra/newview/llperfstats.h
@@ -223,7 +223,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, boost::hash<LLUUID>>;
+ using StatsMap = std::unordered_map<LLUUID, StatsArray>;
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)>;
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 31909116c7..a9e3afbc58 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -2122,6 +2122,11 @@ void LLPreviewLSL::onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType t
if (compile_target.empty())
{
+ if (!is_lua)
+ {
+ // No language info from inventory metadata; fall back to content analysis.
+ is_lua = is_lua_script(std::string(&buffer[0], file_length));
+ }
compile_target = is_lua ? "luau" : "mono";
}
@@ -2432,6 +2437,29 @@ void LLLiveLSLEditor::loadScriptText(const LLUUID &uuid, LLAssetType::EType type
script_name = inv_item->getName();
}
mScriptEd->setScriptName(script_name);
+
+ // Detect language from inventory metadata, with content-based fallback.
+ bool is_lua = false;
+ std::string compile_target;
+ if (inv_item)
+ {
+ U8 subtype = inv_item->getInventorySubType();
+ std::string runtime = inv_item->getRuntime();
+ is_lua = (subtype == SST_LUA);
+ if (!is_lua && (runtime == "luau"))
+ compile_target = "lsl-luau";
+ else
+ compile_target = runtime;
+ }
+ if (compile_target.empty())
+ {
+ if (!is_lua)
+ is_lua = is_lua_script(std::string(&buffer[0], file_length));
+ compile_target = is_lua ? "luau" : "mono";
+ }
+ mScriptEd->mCompileTarget->setValue(compile_target);
+ mScriptEd->mEditor->setLuauLanguage(is_lua);
+ mScriptEd->processKeywords(is_lua);
}
diff --git a/indra/newview/llscriptruntimeperms.h b/indra/newview/llscriptruntimeperms.h
index 300304c21b..6350b61d08 100644
--- a/indra/newview/llscriptruntimeperms.h
+++ b/indra/newview/llscriptruntimeperms.h
@@ -24,10 +24,7 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLSCRIPTRUNTIME_PERMS_H
-#define LL_LLSCRIPTRUNTIME_PERMS_H
-
-#include <boost/array.hpp>
+#pragma once
typedef struct _script_perm {
std::string question;
@@ -37,12 +34,12 @@ typedef struct _script_perm {
question(q), permbit(b), caution(c) {}
} script_perm_t;
-const U32 NUM_SCRIPT_PERMISSIONS = 18;
+const U32 NUM_SCRIPT_PERMISSIONS = 19;
const S32 SCRIPT_PERMISSION_DEBIT = 0;
const S32 SCRIPT_PERMISSION_TRIGGER_ANIMATION = 3;
const S32 SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS = 14;
-static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{
+static const std::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSIONS = {{
_script_perm("ScriptTakeMoney", (0x1 << 1), true),
_script_perm("ActOnControlInputs", (0x1 << 2), false),
_script_perm("RemapControlInputs", (0x1 << 3), false),
@@ -60,7 +57,7 @@ static const boost::array<script_perm_t, NUM_SCRIPT_PERMISSIONS> SCRIPT_PERMISSI
_script_perm("OverrideYourAnimations", (0x1 << 15), false),
_script_perm("ScriptReturnObjects", (0x1 << 16), false),
_script_perm("ForceSitAvatar", (0x1 << 17), false),
- _script_perm("ChangeEnvSettings", (0x1 << 18), false)
+ _script_perm("ChangeEnvSettings", (0x1 << 18), false),
+ _script_perm("PrivilegedLandAccess",(0x1 << 19), true)
} };
-#endif // LL_LLSCRIPTRUNTIME_PERMS_H
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index a624682e11..7cf626f632 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -6193,6 +6193,15 @@ void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** use
node->mCategory = category;
node->mName.assign(name);
node->mDescription.assign(desc);
+
+ LLViewerObject* obj = node->getObject();
+ if (obj && LLViewerObject::isObjectInPendingUpdate(owner_id, obj))
+ {
+ // current response doesn't return modify permissions flags,
+ // so we should request it separately if needed
+ obj->requestObjectUpdate();
+ }
+
}
dialog_refresh_all();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 00a34c802b..69f60ee6ce 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -29,6 +29,11 @@
#include "llappviewer.h"
#include "llstartup.h"
+#if LL_VELOPACK && LL_WINDOWS
+#include "llvelopack.h"
+#include <shellapi.h>
+#endif
+
#if LL_WINDOWS
# include <process.h> // _spawnl()
#else
@@ -265,6 +270,7 @@ std::unique_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::P
void login_show();
void login_callback(S32 option, void* userdata);
+void uninstall_nsis_if_required();
void show_release_notes_if_required();
void show_first_run_dialog();
bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
@@ -920,6 +926,7 @@ bool idle_startup()
LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL;
#endif
do_startup_frame();
+ uninstall_nsis_if_required();
timeout.reset();
return false;
}
@@ -2600,6 +2607,67 @@ void release_notes_coro(const std::string url)
LLWeb::loadURLInternal(url);
}
+/**
+* Check if this is a fresh velopack install and
+* if uninstallation of old viewer is needed.
+*/
+void uninstall_nsis_if_required()
+{
+#if LL_VELOPACK && LL_WINDOWS
+ bool checked_for_legacy_install = gSavedSettings.getBOOL("PreviousInstallChecked");
+ if (checked_for_legacy_install)
+ {
+ return;
+ }
+ gSavedSettings.setBOOL("PreviousInstallChecked", true);
+
+ LL_INFOS() << "Looking for previous NSIS installs" << LL_ENDL;
+
+ S32 found_major = 0;
+ S32 found_minor = 0;
+ S32 found_patch = 0;
+ U64 found_build = 0;
+
+ if (!get_nsis_version(found_major, found_minor, found_patch, found_build))
+ {
+ return;
+ }
+
+ LLVersionInfo* ver_inst = LLVersionInfo::getInstance();
+
+ if (found_major > ver_inst->getMajor())
+ {
+ LL_INFOS() << "Found installed nsis version that is newer" << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
+ return;
+ }
+
+ if (found_major == ver_inst->getMajor()
+ && found_minor > ver_inst->getMinor())
+ {
+ LL_INFOS() << "Found installed nsis version that is newer" << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
+ return;
+ }
+
+ if (found_major == ver_inst->getMajor()
+ && found_minor == ver_inst->getMinor()
+ && found_patch > ver_inst->getPatch())
+ {
+ LL_INFOS() << "Found installed nsis version that is newer" << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
+ return;
+ }
+
+ // Assume that nsis is going to be something like x.x.x, while velopack is x.x.(x+1),
+ // so there is no point to check build.
+ LL_INFOS() << "Found NSIS install " << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
+
+ clear_nsis_links();
+
+ LLSD args;
+ args["VERSION"] = llformat("%d.%d.%d", found_major, found_minor, found_patch);
+ LLNotificationsUtil::add("FoundLegacyNsisInstallation", args);
+#endif
+}
+
void validate_release_notes_coro(const std::string url)
{
LLVersionInfo& versionInfo(LLVersionInfo::instance());
@@ -2633,15 +2701,24 @@ void show_release_notes_if_required()
// below. If viewer release notes stop working, might be because that
// LLEventMailDrop got moved out of LLVersionInfo and hasn't yet been
// instantiated.
- if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion)
- && LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds
- && gSavedSettings.getBOOL("UpdaterShowReleaseNotes")
- && !gSavedSettings.getBOOL("FirstLoginThisInstall"))
+ if (release_notes_shown
+ || LLVersionInfo::instance().getChannelAndVersion() == gLastRunVersion
+ || gSavedSettings.getBOOL("FirstLoginThisInstall")) // New users don't need to see release notes
+ {
+ return;
+ }
+ S32 mode = gSavedSettings.getS32("UpdaterShowReleaseNotes");
+ if (mode == 0)
+ {
+ return;
+ }
+ if (mode == 2 // Show even for test builds
+ || LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER) // don't show Release Notes for the test builds
+
{
#if LL_RELEASE_FOR_DOWNLOAD
- if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")
- && !LLAppViewer::instance()->isUpdaterMissing())
+ if (!gSavedSettings.getBOOL("CmdLineSkipUpdater"))
{
// Instantiate a "relnotes" listener which assumes any arriving event
// is the release notes URL string. Since "relnotes" is an
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index b0b929a3ef..2042ab2187 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -341,7 +341,7 @@ bool LLTextureCacheRemoteWorker::doRead()
if (!done && (mState == LOCAL))
{
llassert(local_size != 0); // we're assuming there is a non empty local file here...
- if (!mDataSize || mDataSize > local_size)
+ if (mDataSize <= 0 || mDataSize > local_size)
{
mDataSize = local_size;
}
@@ -986,6 +986,8 @@ void LLTextureCache::setReadOnly(bool read_only)
// Returns the unused amount of max_size if any
S64 LLTextureCache::initCache(ELLPath location, S64 max_size, bool texture_cache_mismatch)
{
+ LL_PROFILE_ZONE_SCOPED;
+
llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
S64 entries_size = (max_size * 36) / 100; //0.36 * max_size
diff --git a/indra/newview/lltoastscriptquestion.cpp b/indra/newview/lltoastscriptquestion.cpp
index 25dc0982b8..55e178e084 100644
--- a/indra/newview/lltoastscriptquestion.cpp
+++ b/indra/newview/lltoastscriptquestion.cpp
@@ -48,7 +48,12 @@ bool LLToastScriptQuestion::postBuild()
LLTextBox* mFooter = getChild<LLTextBox>("bottom_info_message");
mMessage->setValue(mNotification->getMessage());
- mFooter->setValue(mNotification->getFooter());
+ std::string footer = mNotification->getFooter();
+ mFooter->setValue(footer);
+ if (footer.empty())
+ {
+ mFooter->setVisible(false);
+ }
snapToMessageHeight();
@@ -78,21 +83,69 @@ void LLToastScriptQuestion::snapToMessageHeight()
if (mMessage->getVisible() && mFooter->getVisible())
{
- S32 heightDelta = 0;
- S32 maxTextHeight = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT)
+ S32 height_delta = 0;
+ S32 max_text_height = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT)
+ (mFooter->getFont()->getLineHeight() * MAX_LINES_COUNT);
- LLRect messageRect = mMessage->getRect();
- LLRect footerRect = mFooter->getRect();
+ LLRect message_rect = mMessage->getRect();
+
+ S32 old_message_height = message_rect.getHeight();
+ S32 new_message_height = mMessage->getTextBoundingRect().getHeight();
+ S32 new_footer_height = mFooter->getTextBoundingRect().getHeight();
+
+ constexpr S32 FOOTER_PADDING = 8; // new height should include padding for newly added footer
+ S32 required_text_height = new_message_height + new_footer_height + FOOTER_PADDING;
+ S32 new_text_height = llmin(required_text_height, max_text_height);
+
+ // Footer was invisible, so use old_message_height for old height
+ height_delta = new_text_height - old_message_height;
+
+ reshape( getRect().getWidth(), llmax(getRect().getHeight() + height_delta, MIN_PANEL_HEIGHT));
+
+ // Floater was resized, now resize and shift children
+ // Message follows top, so it's top is in a correct position, but needs to be resized down
+ S32 message_delta = new_message_height - old_message_height;
+ message_rect = mMessage->getRect(); // refresh since it might have changed after reshape
+ message_rect.mBottom = message_rect.mBottom - message_delta;
+ mMessage->setRect(message_rect);
+ mMessage->needsReflow();
+ // Button panel should stay the same size, just translate it
+ LLPanel* panel = getChild<LLPanel>("buttons_panel");
+ panel->translate(0, -message_delta);
+ // Footer should be both moved and resized
+ LLRect footer_rect = mFooter->getRect();
+ footer_rect.mTop = footer_rect.mTop - message_delta;
+ footer_rect.mBottom = footer_rect.mTop - new_footer_height;
+ mFooter->setRect(footer_rect);
+ mFooter->needsReflow();
+ }
+ else if (mMessage->getVisible())
+ {
+ S32 height_delta = 0;
+ S32 max_text_height = (mMessage->getFont()->getLineHeight() * MAX_LINES_COUNT);
+
+ LLRect message_rect = mMessage->getRect();
+
+ S32 old_message_height = message_rect.getHeight();
+ S32 new_message_height = mMessage->getTextBoundingRect().getHeight();
- S32 oldTextHeight = messageRect.getHeight() + footerRect.getHeight();
+ S32 new_text_height = llmin(new_message_height, max_text_height);
- S32 requiredTextHeight = mMessage->getTextBoundingRect().getHeight() + mFooter->getTextBoundingRect().getHeight();
- S32 newTextHeight = llmin(requiredTextHeight, maxTextHeight);
+ // Footer was invisible, so use old_message_height for old height
+ height_delta = new_text_height - old_message_height;
- heightDelta = newTextHeight - oldTextHeight - heightDelta;
+ reshape(getRect().getWidth(), llmax(getRect().getHeight() + height_delta, MIN_PANEL_HEIGHT));
- reshape( getRect().getWidth(), llmax(getRect().getHeight() + heightDelta, MIN_PANEL_HEIGHT));
+ // Floater was resized, now resize and shift children
+ // Message follows top, so it's top is in a correct position, but needs to be resized down
+ S32 message_delta = new_message_height - old_message_height;
+ message_rect = mMessage->getRect(); // refresh since it might have changed after reshape
+ message_rect.mBottom = message_rect.mBottom - message_delta;
+ mMessage->setRect(message_rect);
+ mMessage->needsReflow();
+ // Button panel should stay the same size, just translate it
+ LLPanel* panel = getChild<LLPanel>("buttons_panel");
+ panel->translate(0, -message_delta);
}
}
diff --git a/indra/newview/llvelopack.cpp b/indra/newview/llvelopack.cpp
new file mode 100644
index 0000000000..28e989c4ba
--- /dev/null
+++ b/indra/newview/llvelopack.cpp
@@ -0,0 +1,1201 @@
+/**
+ * @file llvelopack.cpp
+ * @brief Velopack installer and update framework integration
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#if LL_VELOPACK
+
+#include "llviewerprecompiledheaders.h"
+#include "llvelopack.h"
+#include "llstring.h"
+#include "llcorehttputil.h"
+#include "llversioninfo.h"
+
+#include <boost/json.hpp>
+#include <fstream>
+#include <unordered_map>
+#include "llnotificationsutil.h"
+#include "llviewercontrol.h"
+#include "llappviewer.h"
+#include "llcoros.h"
+
+#include "Velopack.h"
+
+#if LL_WINDOWS
+#include <windows.h>
+#include <shlobj.h>
+#include <shobjidl.h>
+#include <shlwapi.h>
+#include <objbase.h>
+#include <filesystem>
+
+#pragma comment(lib, "shlwapi.lib")
+#pragma comment(lib, "ole32.lib")
+#pragma comment(lib, "shell32.lib")
+#endif // LL_WINDOWS
+
+// Common state
+static std::string sUpdateUrl;
+static std::function<void(int)> sProgressCallback;
+static vpkc_update_manager_t* sUpdateManager = nullptr;
+static vpkc_update_info_t* sPendingUpdate = nullptr; // Downloaded, ready to apply
+static vpkc_update_info_t* sPendingCheckInfo = nullptr; // Checked, awaiting user response
+static vpkc_update_source_t* sUpdateSource = nullptr;
+static LLNotificationPtr sDownloadingNotification;
+static bool sRestartAfterUpdate = false;
+static bool sIsRequired = false; // Is the pending check a required update?
+static std::string sReleaseNotesUrl;
+static std::string sTargetVersion; // Velopack's actual target version
+
+// Forward declarations
+static void show_required_update_prompt();
+static void show_downloading_notification(const std::string& version);
+static void ensure_update_manager(bool allow_downgrade);
+static void velopack_download_pending_update();
+static std::unordered_map<std::string, std::string> sAssetUrlMap; // basename -> original absolute URL
+
+//
+// Custom update source helpers
+//
+
+static std::string extract_basename(const std::string& url)
+{
+ // Strip query params / fragment
+ std::string path = url;
+ auto qpos = path.find('?');
+ if (qpos != std::string::npos) path = path.substr(0, qpos);
+ auto fpos = path.find('#');
+ if (fpos != std::string::npos) path = path.substr(0, fpos);
+
+ auto spos = path.rfind('/');
+ if (spos != std::string::npos && spos + 1 < path.size())
+ return path.substr(spos + 1);
+ return path;
+}
+
+static void rewrite_asset_urls(boost::json::value& jv)
+{
+ if (jv.is_object())
+ {
+ auto& obj = jv.as_object();
+ auto it = obj.find("FileName");
+ if (it != obj.end() && it->value().is_string())
+ {
+ std::string filename(it->value().as_string());
+ if (filename.find("://") != std::string::npos)
+ {
+ std::string basename = extract_basename(filename);
+ sAssetUrlMap[basename] = filename;
+ it->value() = basename;
+ LL_DEBUGS("Velopack") << "Rewrote FileName: " << basename << LL_ENDL;
+ }
+ }
+ for (auto& kv : obj)
+ {
+ rewrite_asset_urls(kv.value());
+ }
+ }
+ else if (jv.is_array())
+ {
+ for (auto& elem : jv.as_array())
+ {
+ rewrite_asset_urls(elem);
+ }
+ }
+}
+
+static std::string rewrite_release_feed(const std::string& json_str)
+{
+ boost::json::value jv = boost::json::parse(json_str);
+ rewrite_asset_urls(jv);
+ return boost::json::serialize(jv);
+}
+
+static std::string download_url_raw(const std::string& url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ auto httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("VelopackSource", httpPolicy);
+ auto httpRequest = std::make_shared<LLCore::HttpRequest>();
+ auto httpOpts = std::make_shared<LLCore::HttpOptions>();
+ httpOpts->setFollowRedirects(true);
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts);
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("Velopack") << "HTTP request failed for " << url << ": " << status.toString() << LL_ENDL;
+ return {};
+ }
+
+ const LLSD::Binary& rawBody = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
+ return std::string(rawBody.begin(), rawBody.end());
+}
+
+static bool download_url_to_file(const std::string& url, const std::string& local_path)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ auto httpAdapter = std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("VelopackDownload", httpPolicy);
+ auto httpRequest = std::make_shared<LLCore::HttpRequest>();
+ auto httpOpts = std::make_shared<LLCore::HttpOptions>();
+ httpOpts->setFollowRedirects(true);
+ httpOpts->setTransferTimeout(1200);
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts);
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("Velopack") << "Download failed for " << url << ": " << status.toString() << LL_ENDL;
+ return false;
+ }
+
+ const LLSD::Binary& rawBody = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
+ llofstream outFile(local_path, std::ios::binary | std::ios::trunc);
+ if (!outFile.is_open())
+ {
+ LL_WARNS("Velopack") << "Failed to open file for writing: " << local_path << LL_ENDL;
+ return false;
+ }
+ outFile.write(reinterpret_cast<const char*>(rawBody.data()), rawBody.size());
+ outFile.close();
+ return true;
+}
+
+//
+// Custom source callbacks
+//
+
+static char* custom_get_release_feed(void* user_data, const char* releases_name)
+{
+ std::string base = sUpdateUrl;
+ if (!base.empty() && base.back() == '/')
+ base.pop_back();
+ std::string url = base + "/" + releases_name;
+ LL_INFOS("Velopack") << "Fetching release feed: " << url << LL_ENDL;
+
+ std::string json_str = download_url_raw(url);
+ if (json_str.empty())
+ {
+ return nullptr;
+ }
+
+ try
+ {
+ std::string rewritten = rewrite_release_feed(json_str);
+ char* result = static_cast<char*>(malloc(rewritten.size() + 1));
+ if (result)
+ {
+ memcpy(result, rewritten.c_str(), rewritten.size() + 1);
+ }
+ return result;
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS("Velopack") << "Failed to parse/rewrite release feed: " << e.what() << LL_ENDL;
+ // Return original unmodified feed as fallback
+ char* result = static_cast<char*>(malloc(json_str.size() + 1));
+ if (result)
+ {
+ memcpy(result, json_str.c_str(), json_str.size() + 1);
+ }
+ return result;
+ }
+}
+
+static void custom_free_release_feed(void* user_data, char* feed)
+{
+ free(feed);
+}
+
+static std::string sPreDownloadedAssetPath;
+
+static bool custom_download_asset(void* user_data,
+ const vpkc_asset_t* asset,
+ const char* local_path,
+ size_t progress_callback_id)
+{
+ // The asset has already been downloaded at the coroutine level (before vpkc_download_updates).
+ // This callback just copies the pre-downloaded file to where Velopack expects it.
+ // We cannot use getRawAndSuspend here — coroutine context is lost through the Rust FFI boundary.
+ if (sPreDownloadedAssetPath.empty())
+ {
+ LL_WARNS("Velopack") << "No pre-downloaded asset available" << LL_ENDL;
+ return false;
+ }
+
+ std::string filename = asset->FileName ? asset->FileName : "";
+ LL_INFOS("Velopack") << "Download asset callback: filename=" << filename
+ << " local_path=" << local_path
+ << " size=" << asset->Size << LL_ENDL;
+ vpkc_source_report_progress(progress_callback_id, 0);
+
+ std::ifstream src(sPreDownloadedAssetPath, std::ios::binary);
+ llofstream dst(local_path, std::ios::binary | std::ios::trunc);
+ if (!src.is_open() || !dst.is_open())
+ {
+ LL_WARNS("Velopack") << "Failed to open files for copy" << LL_ENDL;
+ return false;
+ }
+
+ dst << src.rdbuf();
+ dst.close();
+ src.close();
+
+ vpkc_source_report_progress(progress_callback_id, 100);
+ LL_INFOS("Velopack") << "Asset copy complete" << LL_ENDL;
+ return true;
+}
+
+//
+// Platform-specific helpers and hooks
+//
+
+#if LL_WINDOWS
+
+static const wchar_t* PROTOCOL_SECONDLIFE = L"secondlife";
+static const wchar_t* PROTOCOL_GRID_INFO = L"x-grid-location-info";
+static std::wstring get_viewer_exe_name()
+{
+ return ll_convert<std::wstring>(gDirUtilp->getExecutableFilename());
+}
+
+static std::wstring get_install_dir()
+{
+ wchar_t path[MAX_PATH];
+ GetModuleFileNameW(NULL, path, MAX_PATH);
+ PathRemoveFileSpecW(path);
+ return path;
+}
+
+static std::wstring get_app_name()
+{
+ // Match viewer_manifest.py app_name() logic: release channel uses "Viewer"
+ // suffix instead of "Release" for display purposes (shortcuts, uninstall, etc.)
+ std::wstring channel = LL_TO_WSTRING(LL_VIEWER_CHANNEL);
+ std::wstring release_suffix = L" Release";
+ if (channel.size() >= release_suffix.size() &&
+ channel.compare(channel.size() - release_suffix.size(), release_suffix.size(), release_suffix) == 0)
+ {
+ channel.replace(channel.size() - release_suffix.size(), release_suffix.size(), L" Viewer");
+ }
+ return channel;
+}
+
+static std::wstring get_app_name_oneword()
+{
+ std::wstring name = get_app_name();
+ name.erase(std::remove(name.begin(), name.end(), L' '), name.end());
+ return name;
+}
+
+static std::wstring get_start_menu_path()
+{
+ wchar_t path[MAX_PATH];
+ if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, path)))
+ {
+ return path;
+ }
+ return L"";
+}
+
+static std::wstring get_desktop_path()
+{
+ wchar_t path[MAX_PATH];
+ if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, path)))
+ {
+ return path;
+ }
+ return L"";
+}
+
+static bool create_shortcut(const std::wstring& shortcut_path,
+ const std::wstring& target_path,
+ const std::wstring& arguments,
+ const std::wstring& description,
+ const std::wstring& icon_path)
+{
+ HRESULT hr = CoInitialize(NULL);
+ if (FAILED(hr)) return false;
+
+ IShellLinkW* shell_link = nullptr;
+ hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_IShellLinkW, (void**)&shell_link);
+ if (SUCCEEDED(hr))
+ {
+ shell_link->SetPath(target_path.c_str());
+ shell_link->SetArguments(arguments.c_str());
+ shell_link->SetDescription(description.c_str());
+ shell_link->SetIconLocation(icon_path.c_str(), 0);
+
+ wchar_t work_dir[MAX_PATH];
+ wcscpy_s(work_dir, target_path.c_str());
+ PathRemoveFileSpecW(work_dir);
+ shell_link->SetWorkingDirectory(work_dir);
+
+ IPersistFile* persist_file = nullptr;
+ hr = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file);
+ if (SUCCEEDED(hr))
+ {
+ hr = persist_file->Save(shortcut_path.c_str(), TRUE);
+ persist_file->Release();
+ }
+ shell_link->Release();
+ }
+
+ CoUninitialize();
+ return SUCCEEDED(hr);
+}
+
+static void register_protocol_handler(const std::wstring& protocol,
+ const std::wstring& description,
+ const std::wstring& exe_path)
+{
+ std::wstring key_path = L"SOFTWARE\\Classes\\" + protocol;
+ HKEY hkey;
+
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS)
+ {
+ RegSetValueExW(hkey, NULL, 0, REG_SZ,
+ (BYTE*)description.c_str(), (DWORD)((description.size() + 1) * sizeof(wchar_t)));
+ RegSetValueExW(hkey, L"URL Protocol", 0, REG_SZ, (BYTE*)L"", sizeof(wchar_t));
+ RegCloseKey(hkey);
+ }
+
+ std::wstring icon_key_path = key_path + L"\\DefaultIcon";
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, icon_key_path.c_str(), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS)
+ {
+ std::wstring icon_value = L"\"" + exe_path + L"\"";
+ RegSetValueExW(hkey, NULL, 0, REG_SZ,
+ (BYTE*)icon_value.c_str(), (DWORD)((icon_value.size() + 1) * sizeof(wchar_t)));
+ RegCloseKey(hkey);
+ }
+
+ std::wstring cmd_key_path = key_path + L"\\shell\\open\\command";
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, cmd_key_path.c_str(), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS)
+ {
+ std::wstring cmd_value = L"\"" + exe_path + L"\" -url \"%1\"";
+ RegSetValueExW(hkey, NULL, 0, REG_EXPAND_SZ,
+ (BYTE*)cmd_value.c_str(), (DWORD)((cmd_value.size() + 1) * sizeof(wchar_t)));
+ RegCloseKey(hkey);
+ }
+}
+
+void clear_nsis_links()
+{
+ wchar_t path[MAX_PATH];
+
+ // 1. The 'start' shortcuts set by nsis would be global, like app shortcut:
+ // C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Second Life Viewer\Second Life Viewer.lnk
+ // But it isn't just one link, it's a whole directory that needs to be removed.
+ if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, path)))
+ {
+ std::wstring start_menu_path = path;
+ std::wstring folder_path = start_menu_path + L"\\" + get_app_name();
+
+ std::error_code ec;
+ std::filesystem::path dir(folder_path);
+ if (std::filesystem::exists(dir, ec))
+ {
+ std::filesystem::remove_all(dir, ec);
+ if (ec)
+ {
+ LL_WARNS("Velopack") << "Failed to remove NSIS start menu directory: "
+ << ll_convert_wide_to_string(folder_path) << LL_ENDL;
+ }
+ }
+ }
+
+ // 2. Desktop link, also a global one.
+ // C:\Users\Public\Desktop
+ if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, path)))
+ {
+ std::wstring desktop_path = path;
+ std::wstring shortcut_path = desktop_path + L"\\" + get_app_name() + L".lnk";
+ if (!DeleteFileW(shortcut_path.c_str()))
+ {
+ DWORD error = GetLastError();
+ if (error != ERROR_FILE_NOT_FOUND)
+ {
+ LL_WARNS("Velopack") << "Failed to delete NSIS desktop shortcut: "
+ << ll_convert_wide_to_string(shortcut_path)
+ << " (error: " << error << ")" << LL_ENDL;
+ }
+ }
+ }
+}
+
+static void parse_version(const wchar_t* version_str, int& major, int& minor, int& patch, uint64_t& build)
+{
+ major = minor = patch = 0;
+ build = 0;
+ if (!version_str) return;
+ // Use swscanf for wide strings
+ swscanf(version_str, L"%d.%d.%d.%llu", &major, &minor, &patch, &build);
+}
+
+bool get_nsis_version(
+ int& nsis_major,
+ int& nsis_minor,
+ int& nsis_patch,
+ uint64_t& nsis_build)
+{
+ // Test for presence of NSIS viewer registration, then
+ // attempt to read uninstall info
+ std::wstring app_name_oneword = get_app_name_oneword();
+ std::wstring uninstall_key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + app_name_oneword;
+ HKEY hkey;
+ LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, uninstall_key_path.c_str(), 0, KEY_READ, &hkey);
+ if (result != ERROR_SUCCESS)
+ {
+ return false;
+ }
+
+ // Read DisplayVersion
+ wchar_t version_buf[64] = { 0 };
+ DWORD version_buf_size = sizeof(version_buf);
+ DWORD type = 0;
+ LONG ver_rv = RegGetValueW(hkey, nullptr, L"DisplayVersion", RRF_RT_REG_SZ, &type, version_buf, &version_buf_size);
+
+ if (ver_rv != ERROR_SUCCESS)
+ {
+ RegCloseKey(hkey);
+ return false;
+ }
+
+ parse_version(version_buf, nsis_major, nsis_minor, nsis_patch, nsis_build);
+
+ // Make sure it actually exists and not a dead entry.
+ wchar_t path_buffer[MAX_PATH] = { 0 };
+ DWORD path_buf_size = sizeof(path_buffer);
+ LONG rv = RegGetValueW(hkey, nullptr, L"UninstallString", RRF_RT_REG_SZ, &type, path_buffer, &path_buf_size);
+ RegCloseKey(hkey);
+ if (rv != ERROR_SUCCESS)
+ {
+ return false;
+ }
+ size_t len = wcslen(path_buffer);
+ if (len > 0)
+ {
+ if (path_buffer[0] == L'\"')
+ {
+ // Likely to contain leading "
+ memmove(path_buffer, path_buffer + 1, len * sizeof(wchar_t));
+ }
+ wchar_t* pos = wcsstr(path_buffer, L"uninst.exe");
+ if (pos)
+ {
+ // Likely to contain trailing "
+ pos[wcslen(L"uninst.exe")] = L'\0';
+ }
+ }
+ std::error_code ec;
+ std::filesystem::path path(path_buffer);
+ if (!std::filesystem::exists(path, ec))
+ {
+ return false;
+ }
+
+ // Todo: check codesigning?
+
+ return true;
+}
+
+static void unregister_protocol_handler(const std::wstring& protocol)
+{
+ std::wstring key_path = L"SOFTWARE\\Classes\\" + protocol;
+ RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str());
+}
+
+static void register_uninstall_info(const std::wstring& install_dir,
+ const std::wstring& app_name,
+ const std::wstring& version)
+{
+ std::wstring app_name_oneword = get_app_name_oneword();
+ // Clears velopack's recently created 'uninstall' registry entry.
+ // We are going to use a custom one.
+ // Note that velopack doesn't know about our custom entry.
+ std::wstring key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + app_name_oneword;
+ RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str());
+ // Use a unique key name to avoid conflicts with any existing NSIS-based uninstall info,
+ // which can cause only one of the two entries to show up in the Add/Remove Programs list.
+ // The UI will show DisplayName, so the key name itself is not important to be user-friendly.
+ key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vlpk" + app_name_oneword;
+ HKEY hkey;
+
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
+ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, NULL) == ERROR_SUCCESS)
+ {
+ std::wstring exe_path = install_dir + L"\\" + get_viewer_exe_name();
+ // Update.exe lives one level above the current\ directory where the viewer exe runs
+ std::filesystem::path update_exe = std::filesystem::path(install_dir).parent_path() / L"Update.exe";
+ std::wstring uninstall_cmd = L"\"" + update_exe.wstring() + L"\" --uninstall";
+
+ RegSetValueExW(hkey, L"DisplayName", 0, REG_SZ,
+ (BYTE*)app_name.c_str(), (DWORD)((app_name.size() + 1) * sizeof(wchar_t)));
+ RegSetValueExW(hkey, L"DisplayVersion", 0, REG_SZ,
+ (BYTE*)version.c_str(), (DWORD)((version.size() + 1) * sizeof(wchar_t)));
+ RegSetValueExW(hkey, L"Publisher", 0, REG_SZ,
+ (BYTE*)L"Linden Research, Inc.", 44);
+ RegSetValueExW(hkey, L"UninstallString", 0, REG_SZ,
+ (BYTE*)uninstall_cmd.c_str(), (DWORD)((uninstall_cmd.size() + 1) * sizeof(wchar_t)));
+ RegSetValueExW(hkey, L"DisplayIcon", 0, REG_SZ,
+ (BYTE*)exe_path.c_str(), (DWORD)((exe_path.size() + 1) * sizeof(wchar_t)));
+
+ std::wstring link_url = L"https://support.secondlife.com/contact-support/";
+ RegSetValueExW(hkey, L"HelpLink", 0, REG_SZ,
+ (BYTE*)link_url.c_str(), (DWORD)((link_url.size() + 1) * sizeof(wchar_t)));
+
+ link_url = L"https://secondlife.com/whatis/";
+ RegSetValueExW(hkey, L"URLInfoAbout", 0, REG_SZ,
+ (BYTE*)link_url.c_str(), (DWORD)((link_url.size() + 1) * sizeof(wchar_t)));
+
+ link_url = L"https://secondlife.com/support/downloads/";
+ RegSetValueExW(hkey, L"URLUpdateInfo", 0, REG_SZ,
+ (BYTE*)link_url.c_str(), (DWORD)((link_url.size() + 1) * sizeof(wchar_t)));
+
+ DWORD no_modify = 1;
+ RegSetValueExW(hkey, L"NoModify", 0, REG_DWORD, (BYTE*)&no_modify, sizeof(DWORD));
+ RegSetValueExW(hkey, L"NoRepair", 0, REG_DWORD, (BYTE*)&no_modify, sizeof(DWORD));
+
+ // Format YYYYMMDD
+ wchar_t dateStr[9];
+ time_t t = time(NULL);
+ struct tm tm;
+ localtime_s(&tm, &t);
+ wcsftime(dateStr, 9, L"%Y%m%d", &tm);
+ RegSetValueExW(hkey, L"InstallDate", 0, REG_SZ, (BYTE*)dateStr, (DWORD)((wcslen(dateStr) + 1) * sizeof(wchar_t))); // Let Windows fill in the install date
+
+ // 800 MB, inaccurate, but for a rough idea.
+ // We can check folder size here, but it would take time and
+ // information is of low importance.
+ DWORD estimated_size = 800000;
+ RegSetValueExW(hkey, L"EstimatedSize", 0, REG_DWORD, (BYTE*)&estimated_size, sizeof(DWORD));
+
+ RegCloseKey(hkey);
+ }
+}
+
+static void unregister_uninstall_info()
+{
+ std::wstring app_name_oneword = get_app_name_oneword();
+ std::wstring key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vlpk" + app_name_oneword;
+ RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str());
+}
+
+static void create_shortcuts(const std::wstring& install_dir, const std::wstring& app_name)
+{
+ std::wstring exe_path = install_dir + L"\\" + get_viewer_exe_name();
+ std::wstring start_menu_dir = get_start_menu_path() + L"\\" + app_name;
+ std::wstring desktop_path = get_desktop_path();
+
+ CreateDirectoryW(start_menu_dir.c_str(), NULL);
+
+ create_shortcut(start_menu_dir + L"\\" + app_name + L".lnk",
+ exe_path, L"", app_name, exe_path);
+
+ create_shortcut(desktop_path + L"\\" + app_name + L".lnk",
+ exe_path, L"", app_name, exe_path);
+}
+
+static void remove_shortcuts(const std::wstring& app_name)
+{
+ std::wstring start_menu_dir = get_start_menu_path() + L"\\" + app_name;
+ std::wstring desktop_path = get_desktop_path();
+
+ DeleteFileW((start_menu_dir + L"\\" + app_name + L".lnk").c_str());
+ RemoveDirectoryW(start_menu_dir.c_str());
+ DeleteFileW((desktop_path + L"\\" + app_name + L".lnk").c_str());
+}
+
+static void on_first_run(void* p_user_data, const char* app_version)
+{
+ // Velopack first executes 'after install' hook, then writes registry,
+ // then executes 'on first run' hook.
+ // As we need to clear velopack's 'uninstall' registry entry and use
+ // our own, clean it here instead of on_after_install.
+
+ std::wstring install_dir = get_install_dir();
+ std::wstring app_name = get_app_name();
+
+ int len = MultiByteToWideChar(CP_UTF8, 0, app_version, -1, NULL, 0);
+ std::wstring version(len, 0);
+ MultiByteToWideChar(CP_UTF8, 0, app_version, -1, &version[0], len);
+
+ register_uninstall_info(install_dir, app_name, version);
+}
+
+static void on_after_install(void* user_data, const char* app_version)
+{
+ std::wstring install_dir = get_install_dir();
+ std::wstring app_name = get_app_name();
+ std::wstring exe_path = install_dir + L"\\" + get_viewer_exe_name();
+
+ register_protocol_handler(PROTOCOL_SECONDLIFE, L"URL:Second Life", exe_path);
+ register_protocol_handler(PROTOCOL_GRID_INFO, L"URL:Second Life", exe_path);
+ create_shortcuts(install_dir, app_name);
+}
+
+static void on_before_uninstall(void* user_data, const char* app_version)
+{
+ std::wstring app_name = get_app_name();
+
+ unregister_protocol_handler(PROTOCOL_SECONDLIFE);
+ unregister_protocol_handler(PROTOCOL_GRID_INFO);
+ unregister_uninstall_info();
+ remove_shortcuts(app_name);
+}
+
+static void on_log_message(void* user_data, const char* level, const char* message)
+{
+ OutputDebugStringA("[Velopack] ");
+ OutputDebugStringA(level);
+ OutputDebugStringA(": ");
+ OutputDebugStringA(message);
+ OutputDebugStringA("\n");
+}
+
+#elif LL_DARWIN
+
+// macOS-specific hooks
+// TODO: Implement protocol handler registration via Launch Services
+// TODO: Implement app bundle management
+
+static void on_first_run(void* user_data, const char* app_version)
+{
+}
+
+static void on_after_install(void* user_data, const char* app_version)
+{
+ // macOS handles protocol registration via Info.plist CFBundleURLTypes
+ // No additional registration needed at runtime
+ LL_INFOS("Velopack") << "macOS post-install hook called for version: " << app_version << LL_ENDL;
+}
+
+static void on_before_uninstall(void* user_data, const char* app_version)
+{
+ LL_INFOS("Velopack") << "macOS pre-uninstall hook called for version: " << app_version << LL_ENDL;
+}
+
+static void on_log_message(void* user_data, const char* level, const char* message)
+{
+ LL_INFOS("Velopack") << "[" << level << "] " << message << LL_ENDL;
+}
+
+#endif // LL_WINDOWS / LL_DARWIN
+
+//
+// Common progress callback
+//
+
+static void on_progress(void* user_data, size_t progress)
+{
+ if (sProgressCallback)
+ {
+ sProgressCallback(static_cast<int>(progress));
+ }
+}
+
+static void on_vpk_log(void* p_user_data,
+ const char* psz_level,
+ const char* psz_message)
+{
+ LL_DEBUGS("Velopack") << ll_safe_string(psz_message) << LL_ENDL;
+}
+
+//
+// Version comparison helper
+//
+
+// Compare running version against a VVM version string "major.minor.patch.build".
+// Returns -1 if running < vvm, 0 if equal, 1 if running > vvm.
+static int compare_running_version(const std::string& vvm_version)
+{
+ S32 major = 0, minor = 0, patch = 0;
+ U64 build = 0;
+ sscanf(vvm_version.c_str(), "%d.%d.%d.%llu", &major, &minor, &patch, &build);
+
+ const LLVersionInfo& vi = LLVersionInfo::instance();
+ S32 cur_major = vi.getMajor();
+ S32 cur_minor = vi.getMinor();
+ S32 cur_patch = vi.getPatch();
+ U64 cur_build = vi.getBuild();
+
+ if (cur_major != major) return cur_major < major ? -1 : 1;
+ if (cur_minor != minor) return cur_minor < minor ? -1 : 1;
+ if (cur_patch != patch) return cur_patch < patch ? -1 : 1;
+ if (cur_build != build) return cur_build < build ? -1 : 1;
+ return 0;
+}
+
+//
+// Update manager lifecycle
+//
+
+static void ensure_update_manager(bool allow_downgrade)
+{
+ if (sUpdateManager)
+ return;
+
+ vpkc_update_options_t options = {};
+ options.AllowVersionDowngrade = allow_downgrade;
+ options.ExplicitChannel = nullptr;
+
+ if (!sUpdateSource)
+ {
+ sUpdateSource = vpkc_new_source_custom_callback(
+ custom_get_release_feed,
+ custom_free_release_feed,
+ custom_download_asset,
+ nullptr);
+ }
+
+ vpkc_locator_config_t* locator_ptr = nullptr;
+
+#if LL_DARWIN
+ // Try auto-detection first (works when the app bundle was packaged by vpk
+ // and has UpdateMac + sq.version already present)
+ if (!vpkc_new_update_manager_with_source(sUpdateSource, &options, nullptr, &sUpdateManager))
+ {
+ char err[512];
+ vpkc_get_last_error(err, sizeof(err));
+ LL_INFOS("Velopack") << "Auto-detect failed (" << ll_safe_string(err)
+ << "), falling back to explicit locator" << LL_ENDL;
+
+ // Auto-detection failed — construct an explicit locator.
+ // This handles legacy DMG installs that don't have Velopack's
+ // install state (UpdateMac, sq.version) in the bundle.
+ vpkc_locator_config_t locator = {};
+
+ // The executable lives at <bundle>/Contents/MacOS/<exe>
+ // The app bundle root is two levels up from the executable directory.
+ std::string exe_dir = gDirUtilp->getExecutableDir();
+ std::string bundle_root = exe_dir + "/../..";
+ char resolved[PATH_MAX];
+ if (realpath(bundle_root.c_str(), resolved))
+ {
+ bundle_root = resolved;
+ }
+
+ // Construct a version string in Velopack SemVer format: major.minor.patch-build
+ const LLVersionInfo& vi = LLVersionInfo::instance();
+ std::string current_version = llformat("%d.%d.%d-%llu",
+ vi.getMajor(), vi.getMinor(), vi.getPatch(), vi.getBuild());
+
+ // Create a minimal sq.version manifest so Velopack knows our version.
+ // Proper vpk-packaged builds have this in the bundle already.
+ std::string manifest_path = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, "sq.version");
+ {
+ std::string app_name = LLVersionInfo::instance().getChannel();
+ std::string pack_id = app_name;
+ pack_id.erase(std::remove(pack_id.begin(), pack_id.end(), ' '), pack_id.end());
+
+ std::string nuspec = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<package xmlns=\"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\">\n"
+ " <metadata>\n"
+ " <id>" + pack_id + "</id>\n"
+ " <version>" + current_version + "</version>\n"
+ " <title>" + app_name + "</title>\n"
+ " </metadata>\n"
+ "</package>\n";
+
+ llofstream manifest_file(manifest_path, std::ios::trunc);
+ if (manifest_file.is_open())
+ {
+ manifest_file << nuspec;
+ manifest_file.close();
+ }
+ }
+
+ std::string packages_dir = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, "velopack-packages");
+ LLFile::mkdir(packages_dir);
+
+ locator.RootAppDir = const_cast<char*>(bundle_root.c_str());
+ locator.CurrentBinaryDir = const_cast<char*>(exe_dir.c_str());
+ locator.ManifestPath = const_cast<char*>(manifest_path.c_str());
+ locator.PackagesDir = const_cast<char*>(packages_dir.c_str());
+ locator.UpdateExePath = nullptr;
+ locator.IsPortable = false;
+
+ locator_ptr = &locator;
+
+ LL_INFOS("Velopack") << "Explicit locator: RootAppDir=" << bundle_root
+ << " CurrentBinaryDir=" << exe_dir
+ << " Version=" << current_version << LL_ENDL;
+
+ if (!vpkc_new_update_manager_with_source(sUpdateSource, &options, locator_ptr, &sUpdateManager))
+ {
+ char err2[512];
+ vpkc_get_last_error(err2, sizeof(err2));
+ LL_WARNS("Velopack") << "Failed to create update manager: " << ll_safe_string(err2) << LL_ENDL;
+ }
+ }
+ return;
+#endif
+
+ // Windows: Velopack auto-detection works because the viewer is installed
+ // by Velopack's Setup.exe which creates the proper install structure.
+ if (!vpkc_new_update_manager_with_source(sUpdateSource, &options, nullptr, &sUpdateManager))
+ {
+ char err[512];
+ vpkc_get_last_error(err, sizeof(err));
+ LL_WARNS("Velopack") << "Failed to create update manager: " << ll_safe_string(err) << LL_ENDL;
+ }
+}
+
+//
+// Public API - Cross-platform
+//
+
+bool velopack_initialize()
+{
+ vpkc_set_logger(on_log_message, nullptr);
+ vpkc_app_set_auto_apply_on_startup(false);
+
+#if LL_WINDOWS || LL_DARWIN
+ vpkc_app_set_hook_first_run(on_first_run);
+ vpkc_app_set_hook_after_install(on_after_install);
+ vpkc_app_set_hook_before_uninstall(on_before_uninstall);
+#endif
+
+ vpkc_app_run(nullptr);
+ return true;
+}
+
+// Downloads the update that was found during the check phase.
+// Operates on sPendingCheckInfo which was set by velopack_check_for_updates.
+static void velopack_download_pending_update()
+{
+ if (!sUpdateManager || !sPendingCheckInfo)
+ {
+ LL_WARNS("Velopack") << "No pending check info to download" << LL_ENDL;
+ return;
+ }
+
+ LL_DEBUGS("Velopack") << "Setting up detailed logging";
+ vpkc_set_logger(on_vpk_log, nullptr);
+ LL_CONT << LL_ENDL;
+ LL_INFOS("Velopack") << "Downloading update..." << LL_ENDL;
+
+ // Pre-download the nupkg at the coroutine level where getRawAndSuspend works.
+ // The download callback inside the Rust FFI cannot use coroutine HTTP.
+ std::string asset_filename = sPendingCheckInfo->TargetFullRelease->FileName
+ ? sPendingCheckInfo->TargetFullRelease->FileName : "";
+ std::string asset_url;
+ auto url_it = sAssetUrlMap.find(asset_filename);
+ if (url_it != sAssetUrlMap.end())
+ {
+ asset_url = url_it->second;
+ }
+ else
+ {
+ std::string base = sUpdateUrl;
+ if (!base.empty() && base.back() == '/')
+ base.pop_back();
+ asset_url = base + "/" + asset_filename;
+ }
+
+ sPreDownloadedAssetPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, asset_filename);
+ LL_INFOS("Velopack") << "Pre-downloading " << asset_url
+ << " to " << sPreDownloadedAssetPath << LL_ENDL;
+
+ if (!download_url_to_file(asset_url, sPreDownloadedAssetPath))
+ {
+ LL_WARNS("Velopack") << "Failed to pre-download update asset" << LL_ENDL;
+ sPreDownloadedAssetPath.clear();
+ return;
+ }
+
+ LL_INFOS("Velopack") << "Pre-download complete, handing to Velopack" << LL_ENDL;
+ if (vpkc_download_updates(sUpdateManager, sPendingCheckInfo, on_progress, nullptr))
+ {
+ if (sPendingUpdate)
+ {
+ vpkc_free_update_info(sPendingUpdate);
+ }
+ sPendingUpdate = sPendingCheckInfo;
+ sPendingCheckInfo = nullptr; // Ownership transferred
+ LL_INFOS("Velopack") << "Update downloaded and pending" << LL_ENDL;
+ }
+ else
+ {
+ char descr[512];
+ vpkc_get_last_error(descr, sizeof(descr));
+ LL_WARNS("Velopack") << "Failed to download update: " << ll_safe_string((const char*)descr) << LL_ENDL;
+ }
+}
+
+static void on_downloading_closed(const LLSD& notification, const LLSD& response)
+{
+ sDownloadingNotification = nullptr;
+ if (sIsRequired)
+ {
+ // User closed the downloading dialog during a required update — re-show it
+ show_downloading_notification(sTargetVersion);
+ }
+}
+
+static void show_downloading_notification(const std::string& version)
+{
+ LLSD args;
+ args["VERSION"] = version;
+ sDownloadingNotification = LLNotificationsUtil::add("DownloadingUpdate", args, LLSD(), on_downloading_closed);
+}
+
+static void dismiss_downloading_notification()
+{
+ if (sDownloadingNotification)
+ {
+ LLNotificationsUtil::cancel(sDownloadingNotification);
+ sDownloadingNotification = nullptr;
+ }
+}
+
+static void on_required_update_response(const LLSD& notification, const LLSD& response)
+{
+ LL_INFOS("Velopack") << "Required update acknowledged, starting download" << LL_ENDL;
+ show_downloading_notification(sTargetVersion);
+ LLCoros::instance().launch("VelopackRequiredUpdate", []()
+ {
+ velopack_download_pending_update();
+ dismiss_downloading_notification();
+ if (velopack_is_update_pending())
+ {
+ LL_INFOS("Velopack") << "Required update downloaded, quitting to apply" << LL_ENDL;
+ velopack_request_restart_after_update();
+ LLAppViewer::instance()->requestQuit();
+ }
+ });
+}
+
+static void on_optional_update_response(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0) // "Install"
+ {
+ LL_INFOS("Velopack") << "User accepted optional update, starting download" << LL_ENDL;
+ show_downloading_notification(sTargetVersion);
+ LLCoros::instance().launch("VelopackOptionalUpdate", []()
+ {
+ velopack_download_pending_update();
+ dismiss_downloading_notification();
+ if (velopack_is_update_pending())
+ {
+ LL_INFOS("Velopack") << "Optional update downloaded, quitting to apply" << LL_ENDL;
+ velopack_request_restart_after_update();
+ LLAppViewer::instance()->requestQuit();
+ }
+ });
+ }
+ else
+ {
+ LL_INFOS("Velopack") << "User declined optional update (option=" << option << ")" << LL_ENDL;
+ // Free the check info since user declined
+ if (sPendingCheckInfo)
+ {
+ vpkc_free_update_info(sPendingCheckInfo);
+ sPendingCheckInfo = nullptr;
+ }
+ }
+}
+
+static void show_required_update_prompt()
+{
+ LLSD args;
+ args["VERSION"] = sTargetVersion;
+ args["URL"] = sReleaseNotesUrl;
+ LLNotificationsUtil::add("PauseForUpdate", args, LLSD(), on_required_update_response);
+}
+
+void velopack_check_for_updates(const std::string& required_version, const std::string& relnotes_url)
+{
+ if (sUpdateUrl.empty())
+ {
+ LL_DEBUGS("Velopack") << "No update URL set, skipping update check" << LL_ENDL;
+ return;
+ }
+
+ // Allow downgrades only for rollbacks: VVM requires a version that's
+ // strictly lower than what we're running (e.g., a retracted build).
+ bool has_required = !required_version.empty();
+ int ver_cmp = has_required ? compare_running_version(required_version) : 0;
+ bool allow_downgrade = ver_cmp > 0; // running > required → rollback scenario
+ ensure_update_manager(allow_downgrade);
+ if (!sUpdateManager)
+ return;
+
+ // Ask Velopack to check its feed — this is the source of truth
+ vpkc_update_info_t* update_info = nullptr;
+ vpkc_update_check_t result = vpkc_check_for_updates(sUpdateManager, &update_info);
+
+ if (result != UPDATE_AVAILABLE || !update_info)
+ {
+ LL_INFOS("Velopack") << "No update available from feed (result=" << result << ")" << LL_ENDL;
+ return;
+ }
+
+ // Extract the actual target version from Velopack's feed
+ std::string target_version = update_info->TargetFullRelease->Version
+ ? update_info->TargetFullRelease->Version : "";
+ LL_INFOS("Velopack") << "Update available: " << target_version
+ << " (required_version=" << required_version << ")" << LL_ENDL;
+
+ // Store state for the prompt/download phase
+ sReleaseNotesUrl = relnotes_url;
+ sTargetVersion = target_version;
+ if (sPendingCheckInfo)
+ {
+ vpkc_free_update_info(sPendingCheckInfo);
+ }
+ sPendingCheckInfo = update_info;
+
+ // Determine if this is mandatory: running version is below VVM's required floor
+ bool is_required = ver_cmp < 0; // running < required → must update
+ sIsRequired = is_required;
+
+ if (is_required)
+ {
+ LL_INFOS("Velopack") << "Required update (running below " << required_version
+ << "), prompting user for " << target_version << LL_ENDL;
+ show_required_update_prompt();
+ return;
+ }
+
+ // Optional update — check user preference
+ U32 updater_setting = gSavedSettings.getU32("UpdaterServiceSetting");
+
+ if (updater_setting == 3)
+ {
+ // "Install each update automatically" — download silently, apply on quit
+ LL_INFOS("Velopack") << "Optional update to " << target_version
+ << ", downloading automatically (UpdaterServiceSetting=3)" << LL_ENDL;
+ velopack_download_pending_update();
+ return;
+ }
+
+ // Default / value 1: "Ask me when an optional update is ready to install"
+ LL_INFOS("Velopack") << "Optional update available (" << target_version << "), prompting user" << LL_ENDL;
+ LLSD args;
+ args["VERSION"] = target_version;
+ args["URL"] = relnotes_url;
+ LLNotificationsUtil::add("PromptOptionalUpdate", args, LLSD(), on_optional_update_response);
+}
+
+std::string velopack_get_current_version()
+{
+ if (!sUpdateManager)
+ {
+ return "";
+ }
+
+ char version[64];
+ size_t len = vpkc_get_current_version(sUpdateManager, version, sizeof(version));
+ if (len > 0)
+ {
+ return std::string(version, len);
+ }
+ return "";
+}
+
+bool velopack_is_update_pending()
+{
+ return sPendingUpdate != nullptr;
+}
+
+bool velopack_is_required_update_in_progress()
+{
+ return sIsRequired && sPendingCheckInfo != nullptr;
+}
+
+std::string velopack_get_required_update_version()
+{
+ return sTargetVersion;
+}
+
+bool velopack_should_restart_after_update()
+{
+ return sRestartAfterUpdate;
+}
+
+void velopack_request_restart_after_update()
+{
+ sRestartAfterUpdate = true;
+}
+
+void velopack_apply_pending_update(bool restart)
+{
+ if (!sUpdateManager || !sPendingUpdate || !sPendingUpdate->TargetFullRelease)
+ {
+ LL_WARNS("Velopack") << "Cannot apply update: no pending update or manager" << LL_ENDL;
+ return;
+ }
+
+ LL_INFOS("Velopack") << "Applying pending update (restart=" << restart << ")" << LL_ENDL;
+ vpkc_wait_exit_then_apply_updates(sUpdateManager,
+ sPendingUpdate->TargetFullRelease,
+ false,
+ restart,
+ nullptr, 0);
+}
+
+void velopack_cleanup()
+{
+ if (sUpdateManager)
+ {
+ vpkc_free_update_manager(sUpdateManager);
+ sUpdateManager = nullptr;
+ }
+ if (sUpdateSource)
+ {
+ vpkc_free_source(sUpdateSource);
+ sUpdateSource = nullptr;
+ }
+ if (sPendingUpdate)
+ {
+ vpkc_free_update_info(sPendingUpdate);
+ sPendingUpdate = nullptr;
+ }
+ if (sPendingCheckInfo)
+ {
+ vpkc_free_update_info(sPendingCheckInfo);
+ sPendingCheckInfo = nullptr;
+ }
+ sAssetUrlMap.clear();
+}
+
+void velopack_set_update_url(const std::string& url)
+{
+ sUpdateUrl = url;
+ LL_INFOS("Velopack") << "Update URL set to: " << url << LL_ENDL;
+}
+
+void velopack_set_progress_callback(std::function<void(int)> callback)
+{
+ sProgressCallback = callback;
+}
+
+#endif // LL_VELOPACK
diff --git a/indra/newview/llvelopack.h b/indra/newview/llvelopack.h
new file mode 100644
index 0000000000..d04d0db7dc
--- /dev/null
+++ b/indra/newview/llvelopack.h
@@ -0,0 +1,59 @@
+/**
+ * @file llvelopack.h
+ * @brief Velopack installer and update framework integration
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVELOPACK_H
+#define LL_LLVELOPACK_H
+
+#if LL_VELOPACK
+
+#include <string>
+#include <functional>
+
+bool velopack_initialize();
+void velopack_check_for_updates(const std::string& required_version, const std::string& relnotes_url);
+std::string velopack_get_current_version();
+bool velopack_is_update_pending();
+bool velopack_is_required_update_in_progress();
+std::string velopack_get_required_update_version();
+bool velopack_should_restart_after_update();
+void velopack_request_restart_after_update();
+void velopack_apply_pending_update(bool restart = true);
+void velopack_set_update_url(const std::string& url);
+void velopack_set_progress_callback(std::function<void(int)> callback);
+void velopack_cleanup();
+
+#if LL_WINDOWS
+void clear_nsis_links();
+bool get_nsis_version(
+ int& nsis_major,
+ int& nsis_minor,
+ int& nsis_patch,
+ uint64_t& nsis_build);
+#endif
+
+#endif // LL_VELOPACK
+#endif
+// EOF
diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp
index 0fb18c28ae..bac291cd19 100644
--- a/indra/newview/llversioninfo.cpp
+++ b/indra/newview/llversioninfo.cpp
@@ -55,7 +55,7 @@ LLVersionInfo::LLVersionInfo():
// need to turn it into a quoted string. LL_TO_STRING() does that.
mWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL)),
// instantiate an LLEventMailDrop with canonical name to listen for news
- // from SLVersionChecker
+ // from the Viewer Version Manager
mPump{new LLEventMailDrop("relnotes")},
// immediately listen on mPump, store arriving URL into mReleaseNotes
mStore{new LLStoreListener<std::string>(*mPump, mReleaseNotes)}
diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h
index 8c384565e4..bffee086be 100644
--- a/indra/newview/llversioninfo.h
+++ b/indra/newview/llversioninfo.h
@@ -111,8 +111,8 @@ private:
std::string mReleaseNotes;
// Store unique_ptrs to the next couple things so we don't have to explain
// to every consumer of this header file all the details of each.
- // mPump is the LLEventMailDrop on which we listen for SLVersionChecker to
- // post the release-notes URL from the Viewer Version Manager.
+ // mPump is the LLEventMailDrop on which we listen for the
+ // release-notes URL from the Viewer Version Manager.
std::unique_ptr<LLEventMailDrop> mPump;
// mStore is an adapter that stores the release-notes URL in mReleaseNotes.
std::unique_ptr<LLStoreListener<std::string>> mStore;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a8ed79a8cc..6d825441ca 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -814,6 +814,7 @@ void setting_setup_signal_listener(LLControlGroup& group, const std::string& set
void settings_setup_listeners()
{
+ LL_PROFILE_ZONE_SCOPED;
setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged);
setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainScale", handleTerrainScaleChanged);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 87598d35ad..37ad29a9f3 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -140,7 +140,7 @@
#include "llwindow.h"
#include "llpathfindingmanager.h"
#include "llstartup.h"
-#include "boost/unordered_map.hpp"
+#include <unordered_map>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/json.hpp>
@@ -153,7 +153,7 @@ using namespace LLAvatarAppearanceDefines;
typedef LLPointer<LLViewerObject> LLViewerObjectPtr;
-static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
+static std::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
LLVOAvatar* find_avatar_from_object(LLViewerObject* object);
LLVOAvatar* find_avatar_from_object(const LLUUID& object_id);
@@ -413,7 +413,23 @@ static LLSLMMenuUpdater* gSLMMenuUpdater = NULL;
LLSLMMenuUpdater::LLSLMMenuUpdater()
{
- mMarketplaceListingsItem = gMenuHolder->getChild<LLView>("MarketplaceListings")->getHandle();
+ LLView* me_menu = gMenuHolder->findChild<LLView>("Me");
+ if (!me_menu)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Me' menu in 'menu_viewer'" << LL_ENDL;
+ return;
+ }
+
+ LLView* marketplace_listings = me_menu->findChild<LLView>("MarketplaceListings");
+ if (!marketplace_listings)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'MarketplaceListings' in 'Me' menu" << LL_ENDL;
+ return;
+ }
+
+ mMarketplaceListingsItem = marketplace_listings->getHandle();
}
void LLSLMMenuUpdater::setMerchantMenu()
{
@@ -473,6 +489,8 @@ void check_merchant_status(bool force)
void init_menus()
{
+ LL_PROFILE_ZONE_SCOPED;
+
// Initialize actions
initialize_menus();
@@ -549,7 +567,29 @@ void init_menus()
color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
}
- LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder");
+ LLView* menu_stack = gViewerWindow->getMainView()->findChildView("menu_stack");
+ if (!menu_stack)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find menu_stack in main_view" << LL_ENDL;
+ return;
+ }
+
+ LLView* status_bar_container = menu_stack->findChildView("status_bar_container");
+ if (!status_bar_container)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find status_bar_container in main_view" << LL_ENDL;
+ return;
+ }
+
+ LLView* menu_bar_holder = status_bar_container->findChildView("menu_bar_holder");
+ if (!menu_bar_holder)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find status_bar_container in main_view" << LL_ENDL;
+ return;
+ }
gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
gMenuBarView->setRect(LLRect(0, menu_bar_holder->getRect().mTop, 0, menu_bar_holder->getRect().mTop - MENU_BAR_HEIGHT));
@@ -563,8 +603,33 @@ void init_menus()
// *TODO:Also fix cost in llfolderview.cpp for Inventory menus
const std::string sound_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getSoundUploadCost());
const std::string animation_upload_cost_str = std::to_string(LLAgentBenefitsMgr::current().getAnimationUploadCost());
- gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", sound_upload_cost_str);
- gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", animation_upload_cost_str);
+
+ LLView* main_upload_menu = gMenuHolder->findChild<LLView>("Upload");
+ if (!main_upload_menu)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Upload' menu in 'menu_viewer'" << LL_ENDL;
+ return;
+ }
+
+ LLView* upload_sound = main_upload_menu->findChild<LLView>("Upload Sound");
+ if (!upload_sound)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Upload Sound' menu item in 'Upload' menu" << LL_ENDL;
+ return;
+ }
+ upload_sound->setLabelArg("[COST]", sound_upload_cost_str);
+
+ LLView* upload_anim = main_upload_menu->findChild<LLView>("Upload Animation");
+ if (!upload_anim)
+ {
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Can't find 'Upload Animation' menu item in 'Upload' menu" << LL_ENDL;
+ return;
+ }
+ upload_anim->setLabelArg("[COST]", animation_upload_cost_str);
+
gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", true);
gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", true);
@@ -572,13 +637,6 @@ void init_menus()
gDetachAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach", true);
gDetachHUDAvatarMenu = gMenuHolder->getChild<LLMenuGL>("Avatar Detach HUD", true);
- // Don't display the Memory console menu if the feature is turned off
- LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", true);
- if (memoryMenu)
- {
- memoryMenu->setVisible(false);
- }
-
gMenuBarView->createJumpKeys();
// Let land based option enable when parcel changes
@@ -2963,7 +3021,7 @@ void handle_object_show_original()
static void init_default_item_label(LLUICtrl* ctrl)
{
const std::string& item_name = ctrl->getName();
- boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ std::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
if (it == sDefaultItemLabels.end())
{
// *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value
@@ -2979,7 +3037,7 @@ static void init_default_item_label(LLUICtrl* ctrl)
static LLStringExplicit get_default_item_label(const std::string& item_name)
{
LLStringExplicit res("");
- boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ std::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
if (it != sDefaultItemLabels.end())
{
res = it->second;
@@ -9692,6 +9750,8 @@ void initialize_spellcheck_menu()
void initialize_menus()
{
+ LL_PROFILE_ZONE_SCOPED;
+
// A parameterized event handler used as ctrl-8/9/0 zoom controls below.
class LLZoomer : public view_listener_t
{
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index cae4b1860c..ad7792f8ff 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5747,28 +5747,40 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
args["NAME"] = clean_owner_name;
S32 known_questions = 0;
bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit;
+ bool caution_enabled = gSavedSettings.getBOOL("PermissionsCautionEnabled");
// check the received permission flags against each permission
+ std::string warning_msg;
for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS)
{
if (questions & script_perm.permbit)
{
- count++;
known_questions |= script_perm.permbit;
// check whether permission question should cause special caution dialog
caution |= (script_perm.caution);
- if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit)
+ // Cautions go into top part of the dialog, questions go into the footer
+ if (caution_enabled && script_perm.caution)
+ {
+ warning_msg += "\n" + LLTrans::getString(script_perm.question + "Caution") + "\n";
continue;
+ }
if (LLTrans::getString(script_perm.question).empty())
{
continue;
}
- script_question += " " + LLTrans::getString(script_perm.question) + "\n";
+ count++;
+ script_question += "\n " + LLTrans::getString(script_perm.question);
}
}
+ if (!warning_msg.empty())
+ {
+ LLStringUtil::format(warning_msg, args);
+ args["WARNINGS"] = warning_msg;
+ }
+
args["QUESTIONS"] = script_question;
if (known_questions != questions)
@@ -5793,12 +5805,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
// check whether cautions are even enabled or not
const char* notification = "ScriptQuestion";
- if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+ if(caution && caution_enabled)
{
- args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : "";
+ args["FOOTERTEXT"] = (count > 0) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n" + script_question : "";
notification = "ScriptQuestionCaution";
}
- else if(experienceid.notNull())
+ else if (experienceid.notNull())
{
payload["experience"]=experienceid;
LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index 890580ddff..6cb3aee20c 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -575,6 +575,7 @@ std::string LLGridManager::getGridLoginID()
std::string LLGridManager::getUpdateServiceURL()
{
+ auto env_update_service = LLStringUtil::getoptenv("SL_UPDATE_SERVICE");
std::string update_url_base = gSavedSettings.getString("CmdLineUpdateService");;
if ( !update_url_base.empty() )
{
@@ -582,6 +583,13 @@ std::string LLGridManager::getUpdateServiceURL()
<< "Update URL base overridden from command line: " << update_url_base
<< LL_ENDL;
}
+ else if (env_update_service && env_update_service->find("http") != std::string::npos)
+ {
+ update_url_base = *env_update_service;
+ LL_INFOS("UpdaterService", "GridManager")
+ << "Update URL base overridden from SL_UPDATE_SERVICE environment variable: " << update_url_base
+ << LL_ENDL;
+ }
else if ( mGridList[mGrid].has(GRID_UPDATE_SERVICE_URL) )
{
update_url_base = mGridList[mGrid][GRID_UPDATE_SERVICE_URL].asString();
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index d280f74fc7..12583e81da 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -130,6 +130,7 @@ F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motio
F64Seconds LLViewerObject::sMaxRegionCrossingInterpolationTime(1.0);// For motion interpolation: don't interpolate over this time on region crossing
std::map<std::string, U32> LLViewerObject::sObjectDataMap;
+std::unordered_map<LLUUID, std::vector<LLViewerObject*>> LLViewerObject::sPendingUpdatesByOwner;
// The maximum size of an object extra parameters binary (packed) block
#define MAX_OBJECT_PARAMS_SIZE 1024
@@ -521,6 +522,8 @@ void LLViewerObject::markDead()
mReflectionProbe = nullptr;
}
+ removeObjectFromPendingUpdate(this);
+
sNumZombieObjects++;
}
}
@@ -7765,6 +7768,61 @@ bool LLViewerObject::isReachable()
return false;
}
+void LLViewerObject::markObjectsForUpdate(const LLUUID& owner_id)
+{
+ sPendingUpdatesByOwner.erase(owner_id);
+ for (S32 i = 0; i < gObjectList.getNumObjects(); ++i)
+ {
+ LLViewerObject* obj = gObjectList.getObject(i);
+ if (!obj || obj->isDead() || obj->isAvatar() || obj->permYouOwner())
+ {
+ continue;
+ }
+ sPendingUpdatesByOwner[owner_id].push_back(obj);
+ }
+}
+
+void LLViewerObject::removeObjectFromPendingUpdate(LLViewerObject* obj)
+{
+ for (auto& [owner_id, objects] : sPendingUpdatesByOwner)
+ {
+ objects.erase(std::remove(objects.begin(), objects.end(), obj), objects.end());
+ }
+}
+
+bool LLViewerObject::isObjectInPendingUpdate(const LLUUID& owner_id, LLViewerObject* obj)
+{
+ if (!obj)
+ {
+ return false;
+ }
+ auto it = sPendingUpdatesByOwner.find(owner_id);
+ if (it != sPendingUpdatesByOwner.end())
+ {
+ const auto& objects = it->second;
+ return std::find(objects.begin(), objects.end(), obj) != objects.end();
+ }
+ return false;
+}
+
+void LLViewerObject::requestObjectUpdate()
+{
+ if (LLViewerRegion* regionp = getRegion())
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RequestMultipleObjects);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU8Fast(_PREHASH_CacheMissType, 0);
+ msg->addU32Fast(_PREHASH_ID, getLocalID());
+ msg->sendReliable(regionp->getHost());
+
+ removeObjectFromPendingUpdate(this);
+ }
+}
+
class ObjectPhysicsProperties : public LLHTTPNode
{
public:
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index db1a412c78..b6ce4c4505 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -624,6 +624,11 @@ public:
void setPhysicsDensity(F32 density);
void setPhysicsRestitution(F32 restitution);
+ static void markObjectsForUpdate(const LLUUID& owner_id);
+ static void removeObjectFromPendingUpdate(LLViewerObject* obj);
+ static bool isObjectInPendingUpdate(const LLUUID& owner_id, LLViewerObject* obj);
+ void requestObjectUpdate();
+
virtual void dump() const;
static U32 getNumZombieObjects() { return sNumZombieObjects; }
@@ -798,6 +803,7 @@ private:
std::unique_ptr<LLReflectionProbeParams> mReflectionProbeParams;
static std::map<std::string, U32> sObjectDataMap;
+ static std::unordered_map<LLUUID, std::vector<LLViewerObject*>> sPendingUpdatesByOwner;
public:
// Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties
U8 mPhysicsShapeType;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 50edb408c7..34e5cc9de8 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -174,7 +174,7 @@ bool LLViewerObjectList::removeFromLocalIDTable(LLViewerObject* objectp)
U32 local_id = objectp->mLocalID;
U64 indexid = (((U64)objectp->mRegionIndex) << 32) | (U64)local_id;
- std::map<U64, LLUUID>::iterator iter = mIndexAndLocalIDToUUID.find(indexid);
+ auto iter = mIndexAndLocalIDToUUID.find(indexid);
if (iter == mIndexAndLocalIDToUUID.end())
{
return false;
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 547ef9fb2d..adc90a0483 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -204,7 +204,7 @@ protected:
uuid_set_t mDeadObjects;
- std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
+ std::unordered_map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
//set of objects that need to update their cost
uuid_set_t mStaleObjectCost;
@@ -221,7 +221,7 @@ protected:
static U32 sSimulatorMachineIndex;
std::map<U64, U32> mIPAndPortToIndex;
- std::map<U64, LLUUID> mIndexAndLocalIDToUUID;
+ std::unordered_map<U64, LLUUID> mIndexAndLocalIDToUUID;
friend class LLViewerObject;
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index f6ee00cb25..d33d426769 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -126,8 +126,6 @@
#include "llfloater.h"
#include <boost/signals2.hpp>
-#include <boost/unordered_set.hpp>
-#include <boost/unordered_map.hpp>
#include <boost/json.hpp>
#include "glm/glm.hpp"
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index cd70f8f9b9..42a587f376 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -104,7 +104,7 @@ S32 LLViewerRegion::sLastCameraUpdated = 0;
S32 LLViewerRegion::sNewObjectCreationThrottle = -1;
LLViewerRegion::vocache_entry_map_t LLViewerRegion::sRegionCacheCleanup;
-typedef std::map<std::string, std::string> CapabilityMap;
+typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> CapabilityMap;
static void log_capabilities(const CapabilityMap &capmap);
@@ -3437,7 +3437,7 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri
}
}
-std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
+std::string LLViewerRegion::getCapabilityDebug(std::string_view name) const
{
CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name);
if (iter == mImpl->mSecondCapabilitiesTracker.end())
@@ -3448,15 +3448,14 @@ std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
return iter->second;
}
-
-bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
+bool LLViewerRegion::isSpecialCapabilityName(std::string_view name)
{
return name == "EventQueueGet" || name == "UntrustedSimulatorMessage";
}
-std::string LLViewerRegion::getCapability(const std::string& name) const
+std::string LLViewerRegion::getCapability(std::string_view name) const
{
- if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
+ if (!capabilitiesReceived() && (name != "Seed") && (name != "ObjectMedia"))
{
LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL;
}
@@ -3464,21 +3463,20 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
if(iter == mImpl->mCapabilities.end())
{
- return "";
+ return {};
}
return iter->second;
}
-bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const
+bool LLViewerRegion::isCapabilityAvailable(std::string_view name) const
{
- if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
+ if (!capabilitiesReceived() && (name != "Seed") && (name != "ObjectMedia"))
{
LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL;
}
- CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
- if(iter == mImpl->mCapabilities.end())
+ if (!mImpl->mCapabilities.contains(name))
{
return false;
}
@@ -3734,9 +3732,14 @@ bool LLViewerRegion::avatarHoverHeightEnabled() const
void log_capabilities(const CapabilityMap &capmap)
{
+ // Copy into sorted map for ordered output
+ using SortedCapabilityMap = std::map<std::string, std::string>;
+ SortedCapabilityMap sorted_capmap;
+ sorted_capmap.insert(capmap.begin(), capmap.end());
+
S32 count = 0;
- CapabilityMap::const_iterator iter;
- for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count)
+ SortedCapabilityMap::const_iterator iter;
+ for (iter = sorted_capmap.begin(); iter != sorted_capmap.end(); ++iter, ++count)
{
if (!iter->second.empty())
{
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index b3ec857907..974bc375b8 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -274,10 +274,10 @@ public:
S32 getNumSeedCapRetries();
void setCapability(const std::string& name, const std::string& url);
void setCapabilityDebug(const std::string& name, const std::string& url);
- bool isCapabilityAvailable(const std::string& name) const;
+ bool isCapabilityAvailable(std::string_view name) const;
// implements LLCapabilityProvider
- virtual std::string getCapability(const std::string& name) const;
- std::string getCapabilityDebug(const std::string& name) const;
+ virtual std::string getCapability(std::string_view name) const;
+ std::string getCapabilityDebug(std::string_view name) const;
// has region received its final (not seed) capability list?
@@ -287,7 +287,7 @@ public:
void setCapabilitiesError();
boost::signals2::connection setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb);
- static bool isSpecialCapabilityName(const std::string &name);
+ static bool isSpecialCapabilityName(std::string_view name);
void logActiveCapabilities() const;
// Utilities to post and get via
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index d39d466205..5193514fe8 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -783,7 +783,11 @@ void send_viewer_stats(bool include_preferences)
fail["failed_resends"] = (S32) gMessageSystem->mFailedResendPackets;
fail["off_circuit"] = (S32) gMessageSystem->mOffCircuitPackets;
fail["invalid"] = (S32) gMessageSystem->mInvalidOnCircuitPackets;
- fail["missing_updater"] = (S32) LLAppViewer::instance()->isUpdaterMissing();
+#if LL_VELOPACK
+ fail["missing_updater"] = false;
+#else
+ fail["missing_updater"] = true;
+#endif
LLSD &inventory = body["inventory"];
inventory["usable"] = gInventory.isInventoryUsable();
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 1e83482752..23915d01fa 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1488,7 +1488,9 @@ bool LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
// from local images, but this might become unsafe in case of changes to fetcher
if (mBoostLevel == BOOST_PREVIEW)
{
- mRawImage->biasedScaleToPowerOfTwo(1024);
+ // A local file with a preview flag likely means mesh's texture upload
+ // which should follow normal upload scaling rules
+ mRawImage->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
}
else
{ // leave black border, do not scale image content
@@ -2574,14 +2576,31 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
S32 best_raw_discard = gl_discard; // Current GL quality level
S32 current_aux_discard = MAX_DISCARD_LEVEL + 1;
S32 best_aux_discard = MAX_DISCARD_LEVEL + 1;
+ LLImageRaw *current_raw_image = nullptr;
if (mIsRawImageValid)
{
- // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels.
+ // If we have an existing raw image, we have a baseline for the raw
+ // and auxiliary quality levels.
+ // Note: we call updateImagesCreateTextures before callbacks, which
+ // leads to destroyRawImage and deletes raw image. So this case
+ // might be rare or even never trigger as there is never a raw image,
+ // only a saved one.
current_raw_discard = mRawDiscardLevel;
best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel);
best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw
current_aux_discard = llmin(current_aux_discard, best_aux_discard);
+ current_raw_image = mRawImage;
+ }
+ else if (mSavedRawImage.notNull())
+ {
+ // We have a saved raw image, we can use that as our baseline for
+ // raw and auxiliary quality levels.
+ current_raw_discard = mSavedRawDiscardLevel;
+ best_raw_discard = llmin(best_raw_discard, mSavedRawDiscardLevel);
+ best_aux_discard = llmin(best_aux_discard, mSavedRawDiscardLevel); // We always decode the aux when we decode the base raw
+ current_aux_discard = llmin(current_aux_discard, best_aux_discard);
+ current_raw_image = mSavedRawImage;
}
else
{
@@ -2646,12 +2665,17 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
if (need_readback)
{
readbackRawImage();
+ if (mIsRawImageValid)
+ {
+ current_raw_discard = mRawDiscardLevel;
+ current_raw_image = mRawImage;
+ }
}
//
// Run raw/auxiliary data callbacks
//
- if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel()))
+ if (run_raw_callbacks && current_raw_image != nullptr && (current_raw_discard <= getMaxDiscardLevel()))
{
// Do callbacks which require raw image data.
//LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL;
@@ -2662,7 +2686,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
{
callback_list_t::iterator curiter = iter++;
LLLoadedCallbackEntry *entryp = *curiter;
- if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel))
+ if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > current_raw_discard))
{
// If we've loaded all the data there is to load or we've loaded enough
// to satisfy the interested party, then this is the last time that
@@ -2673,11 +2697,11 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
{
LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL;
}
- bool final = mRawDiscardLevel <= entryp->mDesiredDiscard;
+ bool final = current_raw_discard <= entryp->mDesiredDiscard;
//LL_INFOS() << "Running callback for " << getID() << LL_ENDL;
- //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL;
- entryp->mLastUsedDiscard = mRawDiscardLevel;
- entryp->mCallback(true, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData);
+ //LL_INFOS() << current_raw_image->getWidth() << "x" << current_raw_image->getHeight() << LL_ENDL;
+ entryp->mLastUsedDiscard = current_raw_discard;
+ entryp->mCallback(true, this, current_raw_image, mAuxRawImage, current_raw_discard, final, entryp->mUserData);
if (final)
{
iter = mLoadedCallbackList.erase(curiter);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index a3c241456d..773ff14e90 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2067,10 +2067,6 @@ void LLViewerWindow::initGLDefaults()
gBox.prerender();
}
-struct MainPanel : public LLPanel
-{
-};
-
void LLViewerWindow::initBase()
{
S32 height = getWindowHeightScaled();
@@ -2109,6 +2105,8 @@ void LLViewerWindow::initBase()
main_view->setShape(full_window);
getRootView()->addChild(main_view);
+ mMainView = main_view;
+
// placeholder widget that controls where "world" is rendered
mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
mPopupView = main_view->getChild<LLPopupView>("popup_holder");
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 9a0bb28f1d..105c1b8baa 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -144,6 +144,10 @@ private:
};
+struct MainPanel : public LLPanel
+{
+};
+
static const U32 MAX_SNAPSHOT_IMAGE_SIZE = 7680; // max snapshot image size 7680 * 7680 UHDTV2
class LLViewerWindow : public LLWindowCallbacks
@@ -248,6 +252,7 @@ public:
// ACCESSORS
//
LLRootView* getRootView() const;
+ MainPanel* getMainView() const { return mMainView; }
// 3D world area in scaled pixels (via UI scale), use for most UI computations
LLRect getWorldViewRectScaled() const;
@@ -500,6 +505,7 @@ private:
LLRect mWorldViewRectRaw; // area of screen for 3D world
LLRect mWorldViewRectScaled; // area of screen for 3D world scaled by UI size
LLRootView* mRootView; // a view of size mWindowRectRaw, containing all child views
+ MainPanel* mMainView; // a view of size mWindowRectRaw, directly containing the base elements of the ui tree
LLView* mFloaterSnapRegion = nullptr;
LLView* mNavBarContainer = nullptr;
LLPanel* mStatusBarContainer = nullptr;
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index d1de2f55da..481f9e3522 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -2496,17 +2496,18 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection)
// callback from llwebrtc
void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
{
+ connectionPtr_t connection = shared_from_this();
LL::WorkQueue::postMaybe(mMainQueue,
- [=, this] {
- if (mShutDown)
+ [=] {
+ if (connection->mShutDown)
{
return;
}
LL_DEBUGS("Voice") << "On Offer Available." << LL_ENDL;
- mChannelSDP = sdp;
- if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START)
+ connection->mChannelSDP = sdp;
+ if (connection->mVoiceConnectionState == VOICE_STATE_WAIT_FOR_SESSION_START)
{
- mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION;
+ connection->mVoiceConnectionState = VOICE_STATE_REQUEST_CONNECTION;
}
});
}
@@ -2523,16 +2524,17 @@ void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
// callback from llwebrtc
void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface* audio_interface)
{
+ connectionPtr_t connection = shared_from_this();
LL::WorkQueue::postMaybe(mMainQueue,
- [=, this] {
- if (mShutDown)
+ [=] {
+ if (connection->mShutDown)
{
return;
}
LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL;
- mWebRTCAudioInterface = audio_interface;
- mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up.
- setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
+ connection->mWebRTCAudioInterface = audio_interface;
+ connection->mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up.
+ connection->setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
});
}
@@ -3207,17 +3209,18 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b
// llwebrtc callback
void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface)
{
+ connectionPtr_t connection = shared_from_this();
LL::WorkQueue::postMaybe(mMainQueue,
- [=, this] {
- if (mShutDown)
+ [=] {
+ if (connection->mShutDown)
{
return;
}
if (data_interface)
{
- mWebRTCDataInterface = data_interface;
- mWebRTCDataInterface->setDataObserver(this);
+ connection->mWebRTCDataInterface = data_interface;
+ connection->mWebRTCDataInterface->setDataObserver(connection.get());
}
});
}
diff --git a/indra/newview/llvvmquery.cpp b/indra/newview/llvvmquery.cpp
new file mode 100644
index 0000000000..12dcc1d04d
--- /dev/null
+++ b/indra/newview/llvvmquery.cpp
@@ -0,0 +1,189 @@
+/**
+ * @file llvvmquery.cpp
+ * @brief Query the Viewer Version Manager (VVM) for update information
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llvvmquery.h"
+
+#include "llcorehttputil.h"
+#include "llcoros.h"
+#include "llevents.h"
+#include "llviewernetwork.h"
+#include "llversioninfo.h"
+#include "llviewercontrol.h"
+#include "llhasheduniqueid.h"
+#include "lluri.h"
+#include "llsys.h"
+
+#if LL_VELOPACK
+#include "llvelopack.h"
+#endif
+
+namespace
+{
+ std::string get_platform_string()
+ {
+#if LL_WINDOWS
+ return "win64";
+#elif LL_DARWIN
+ return "mac64";
+#elif LL_LINUX
+ return "lnx64";
+#else
+ return "unknown";
+#endif
+ }
+
+ std::string get_platform_version()
+ {
+ return LLOSInfo::instance().getOSVersionString();
+ }
+
+ std::string get_machine_id()
+ {
+ unsigned char id[MD5HEX_STR_SIZE];
+ if (llHashedUniqueID(id))
+ {
+ return std::string(reinterpret_cast<char*>(id));
+ }
+ return "unknown";
+ }
+
+ void query_vvm_coro()
+ {
+ // Get base URL from grid manager
+ std::string base_url = LLGridManager::getInstance()->getUpdateServiceURL();
+
+ // We use this for dev testing when working with VVM and working on the updater. Not advisable to uncomment it.
+ //std::string base_url = "https://update.qa.secondlife.io/update";
+
+ if (base_url.empty())
+ {
+ LL_WARNS("VVM") << "No update service URL configured" << LL_ENDL;
+ return;
+ }
+
+ // Gather parameters for VVM query
+ std::string channel = LLVersionInfo::instance().getChannel();
+
+ // We use this for dev testing when working with VVM and working on the updater. Not advisable to uncomment it.
+ // std::string channel = "QA Target for Velopack";
+
+ std::string version = LLVersionInfo::instance().getVersion();
+ std::string platform = get_platform_string();
+ std::string platform_version = get_platform_version();
+ std::string test_ok = gSavedSettings.getBOOL("UpdaterWillingToTest") ? "testok" : "testno";
+ std::string machine_id = get_machine_id();
+
+ // Build URL: {base}/v1.2/{channel}/{version}/{platform}/{platform_version}/{testok}/{uuid}
+ std::string url = base_url + "/v1.2/" +
+ LLURI::escape(channel) + "/" +
+ LLURI::escape(version) + "/" +
+ platform + "/" +
+ LLURI::escape(platform_version) + "/" +
+ test_ok + "/" +
+ machine_id;
+
+ LL_INFOS("VVM") << "Querying VVM: " << url << LL_ENDL;
+
+ // Make HTTP GET request
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter =
+ std::make_shared<LLCoreHttpUtil::HttpCoroutineAdapter>("VVMQuery", httpPolicy);
+ LLCore::HttpRequest::ptr_t request = std::make_shared<LLCore::HttpRequest>();
+
+ LLSD result = adapter->getAndSuspend(request, url);
+
+ // Check HTTP status
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (status.getType() == 404)
+ {
+ LL_INFOS("VVM") << "Unmanaged channel, no updates available" << LL_ENDL;
+ return;
+ }
+ LL_WARNS("VVM") << "VVM query failed: " << status.toString() << LL_ENDL;
+ return;
+ }
+
+ // Read whether this update is required or optional
+ bool update_required = result["required"].asBoolean();
+ std::string relnotes = result["more_info"].asString();
+
+ // Extract update URL for current platform
+ LLSD platforms = result["platforms"];
+ if (platforms.has(platform))
+ {
+ std::string update_url = platforms[platform]["url"].asString();
+#if LL_VELOPACK
+ std::string velopack_url = platforms[platform]["velopack_url"].asString();
+ U32 updater_service = gSavedSettings.getU32("UpdaterServiceSetting");
+ std::string required_version = update_required ? result["version"].asString() : "";
+ // Skip network check if no required version AND user only wants mandatory updates
+ if (!velopack_url.empty() && (update_required || updater_service != 0))
+ {
+ LL_INFOS("VVM") << "Velopack feed URL: " << velopack_url
+ << " required_version: " << required_version << LL_ENDL;
+ velopack_set_update_url(velopack_url);
+
+ LLCoros::instance().launch("VelopackUpdateCheck",
+ [required_version, relnotes]()
+ {
+ velopack_check_for_updates(required_version, relnotes);
+ });
+ }
+ else if (!velopack_url.empty())
+ {
+ LL_INFOS("VVM") << "Optional update skipped (UpdaterServiceSetting=0)" << LL_ENDL;
+ }
+ else
+#endif
+ if (!update_url.empty())
+ {
+ LL_INFOS("VVM") << "Update available at: " << update_url << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS("VVM") << "No update available for platform: " << platform << LL_ENDL;
+ }
+
+ // Post release notes URL to the relnotes event pump
+ if (!relnotes.empty())
+ {
+ LL_INFOS("VVM") << "Release notes URL: " << relnotes << LL_ENDL;
+ LLEventPumps::instance().obtain("relnotes").post(relnotes);
+ }
+ }
+}
+
+void initVVMUpdateCheck()
+{
+ LL_INFOS("VVM") << "Initializing VVM update check" << LL_ENDL;
+ LLCoros::instance().launch("VVMUpdateCheck", &query_vvm_coro);
+}
diff --git a/indra/newview/llvvmquery.h b/indra/newview/llvvmquery.h
new file mode 100644
index 0000000000..977d82af64
--- /dev/null
+++ b/indra/newview/llvvmquery.h
@@ -0,0 +1,42 @@
+/**
+ * @file llvvmquery.h
+ * @brief Query the Viewer Version Manager (VVM) for update information
+ *
+ * $LicenseInfo:firstyear=2025&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2025, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVVMQUERY_H
+#define LL_LLVVMQUERY_H
+
+/**
+ * Initialize the VVM update check.
+ *
+ * This launches a coroutine that queries the Viewer Version Manager (VVM)
+ * to check for available updates. If an update is available, it configures
+ * Velopack with the update URL and initiates the update check/download.
+ *
+ * The release notes URL from the VVM response is posted to the "relnotes"
+ * event pump for display.
+ */
+void initVVMUpdateCheck();
+
+#endif // LL_LLVVMQUERY_H
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index cc593fe7b4..f639024228 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -82,7 +82,7 @@ LLPanelWearableListItem::LLPanelWearableListItem(LLViewerInventoryItem* item, co
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(&typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item");
LLPanelWearableOutfitItem::Params::Params()
: add_btn("add_btn"),
@@ -222,7 +222,7 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name,
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelClothingListItem(&typeid(LLPanelClothingListItem::Params), "clothing_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelClothingListItem(typeid(LLPanelClothingListItem::Params), "clothing_list_item");
LLPanelClothingListItem::Params::Params()
@@ -309,7 +309,7 @@ bool LLPanelClothingListItem::postBuild()
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelBodyPartsListItem(&typeid(LLPanelBodyPartsListItem::Params), "bodyparts_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelBodyPartsListItem(typeid(LLPanelBodyPartsListItem::Params), "bodyparts_list_item");
LLPanelBodyPartsListItem::Params::Params()
@@ -380,7 +380,7 @@ bool LLPanelBodyPartsListItem::postBuild()
return true;
}
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDeletableWearableListItem(&typeid(LLPanelDeletableWearableListItem::Params), "deletable_wearable_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDeletableWearableListItem(typeid(LLPanelDeletableWearableListItem::Params), "deletable_wearable_list_item");
LLPanelDeletableWearableListItem::Params::Params()
: delete_btn("delete_btn")
@@ -467,7 +467,7 @@ void LLPanelAttachmentListItem::updateItem(const std::string& name,
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDummyClothingListItem(&typeid(LLPanelDummyClothingListItem::Params), "dummy_clothing_list_item");
+static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelDummyClothingListItem(typeid(LLPanelDummyClothingListItem::Params), "dummy_clothing_list_item");
LLPanelDummyClothingListItem::Params::Params()
: add_panel("add_panel"),
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c93cb7822e..ba43e80eda 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2601,18 +2601,6 @@ function="World.EnvPreset"
parameter="fast timers" />
</menu_item_check>
<menu_item_check
- label="Memory"
- name="Memory"
- shortcut="control|shift|0"
- use_mac_ctrl="true">
- <menu_item_check.on_check
- function="Advanced.CheckConsole"
- parameter="memory view" />
- <menu_item_check.on_click
- function="Advanced.ToggleConsole"
- parameter="memory view" />
- </menu_item_check>
- <menu_item_check
label="Scene Statistics"
name="Scene Statistics">
<menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index e8da8a6322..b820ede964 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -202,6 +202,16 @@ No tutorial is currently available.
<notification
icon="alertmodal.tga"
+ name="FoundLegacyNsisInstallation"
+ type="alertmodal">
+ [APP_NAME] found an installation of an older version [VERSION]. To uninstall the older version, please follow [https://community.secondlife.com/knowledgebase/english/how-to-uninstall-and-reinstall-second-life-r524 this manual].
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="LoginFailedNoNetwork"
type="alertmodal">
<tag>fail</tag>
@@ -4423,6 +4433,14 @@ Click OK to download and install.
<notification
icon="alertmodal.tga"
+ name="DownloadingUpdate"
+ type="alertmodal">
+Downloading update [VERSION]...
+The viewer will restart once the download is complete.
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="OptionalUpdateReady"
type="alertmodal">
Version [VERSION] has been downloaded and is ready to install.
@@ -8596,10 +8614,10 @@ Scripts associated with this experience will be able to do the following on regi
priority="critical"
persist="true"
type="notify">
-Warning: The object &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos; wants total access to your Linden Dollars account. If you allow access, it can remove funds from your account at any time, or empty your account completely, on an ongoing basis with no additional warnings.
-
-Do not allow access if you do not fully understand why it wants access to your account.
+Warning:
+[WARNINGS]
+Do not allow access if you do not fully understand why it wants access to your account.
<tag>confirm</tag>
<form name="form">
<button
@@ -8612,9 +8630,7 @@ Do not allow access if you do not fully understand why it wants access to your a
name="Deny"
text="Deny"/>
</form>
- <footer>
-[FOOTERTEXT]
- </footer>
+ <footer>[FOOTERTEXT]</footer>
</notification>
<notification
diff --git a/indra/newview/skins/default/xui/en/panel_notification.xml b/indra/newview/skins/default/xui/en/panel_notification.xml
index bfe738f472..eaf638d35f 100644
--- a/indra/newview/skins/default/xui/en/panel_notification.xml
+++ b/indra/newview/skins/default/xui/en/panel_notification.xml
@@ -49,7 +49,7 @@
embedded_items="false"
enabled="false"
follows="left|right|top|bottom"
- height="85"
+ height="85"
layout="topleft"
left="10"
mouse_opaque="false"
@@ -67,16 +67,16 @@
<panel
background_visible="false"
follows="left|right|bottom"
- height="30"
+ height="30"
width="290"
label="control_panel"
layout="topleft"
left="10"
name="control_panel"
top_pad="5">
- <!--
+ <!--
Notes:
- This panel holds buttons of notification. Change of its size can affect the layout of buttons.
+ This panel holds buttons of notification. Change of its size can affect the layout of buttons.
-->
</panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_script_question_toast.xml b/indra/newview/skins/default/xui/en/panel_script_question_toast.xml
index 1b1e31165a..9045e6a8ae 100644
--- a/indra/newview/skins/default/xui/en/panel_script_question_toast.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_question_toast.xml
@@ -6,7 +6,7 @@
bg_alpha_color="PanelNotificationBackground"
bg_opaque_color="PanelNotificationBackground"
chrome="true"
- height="270"
+ height="220"
label="script_question_panel"
layout="topleft"
left="0"
@@ -39,9 +39,9 @@
width="285">
</panel>
<text
- follows="all"
+ follows="left|right|top"
font="SansSerifBold"
- height="55"
+ height="15"
layout="topleft"
mouse_opaque="false"
name="bottom_info_message"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 8e0eea97d1..1860d38b0e 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -518,6 +518,8 @@ http://secondlife.com/support for help fixing this problem.
<string name="reconnect_nearby">You will now be reconnected to Nearby Voice Chat</string>
<string name="ScriptQuestionCautionChatGranted">'[OBJECTNAME]', an object owned by '[OWNERNAME]', located in [REGIONNAME] at [REGIONPOS], has been granted permission to: [PERMISSIONS].</string>
<string name="ScriptQuestionCautionChatDenied">'[OBJECTNAME]', an object owned by '[OWNERNAME]', located in [REGIONNAME] at [REGIONPOS], has been denied permission to: [PERMISSIONS].</string>
+ <string name="ScriptTakeMoneyCaution">The object &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos; wants total access to your Linden Dollars account. If you allow access, it can remove funds from your account at any time, or empty your account completely, on an ongoing basis with no additional warnings.</string>
+ <string name="PrivilegedLandAccessCaution">The object &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos; wants privileged access to your land. If you allow access it may sell your land with no additional warnings.</string>
<string name="AdditionalPermissionsRequestHeader">If you allow access to your account, you will also be allowing the object to:</string>
<string name="ScriptTakeMoney">Take Linden dollars (L$) from you</string>
<string name="ActOnControlInputs">Act on your control inputs</string>
@@ -535,6 +537,7 @@ http://secondlife.com/support for help fixing this problem.
<string name="ChangeYourDefaultAnimations">Change your default animations</string>
<string name="ForceSitAvatar">Force your avatar to sit</string>
<string name="ChangeEnvSettings">Change your environment settings</string>
+ <string name="PrivilegedLandAccess">Sell land on your behalf.</string>
<string name="NotConnected">Not Connected</string>
<string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name -->
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
index acbf019034..3e2e5e70a2 100644
--- a/indra/newview/tests/lldateutil_test.cpp
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -34,16 +34,16 @@
#include "lltrans.h"
#include "llui.h"
-#include <map>
+#include <unordered_map>
// Baked-in return values for getString()
-std::map< std::string, std::string, std::less<>> gString;
+std::unordered_map< std::string, std::string, ll::string_hash, std::equal_to<>> gString;
// Baked-in return values for getCountString()
// map of pairs of input xml_desc and integer count
typedef std::pair< std::string, int > count_string_t;
-std::map< count_string_t, std::string > gCountString;
+std::map<count_string_t, std::string> gCountString;
std::string LLTrans::getString(const std::string_view xml_desc, const LLStringUtil::format_map_t& args, bool def_string)
{
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index b82a58163c..b00b89b9fd 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -223,8 +223,6 @@ bool llHashedUniqueID(unsigned char* id)
//-----------------------------------------------------------------------------
#include "../llappviewer.h"
void LLAppViewer::forceQuit(void) {}
-bool LLAppViewer::isUpdaterMissing() { return true; }
-bool LLAppViewer::waitForUpdater() { return false; }
LLAppViewer * LLAppViewer::sInstance = 0;
//-----------------------------------------------------------------------------
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index bcabc07c5a..21e50f4dcb 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -540,18 +540,6 @@ class Windows_x86_64_Manifest(ViewerManifest):
'*.bat',
'*.tar.xz')))
- with self.prefix(src=os.path.join(pkgdir, "VMP")):
- # include the compiled launcher scripts so that it gets included in the file_list
- self.path('SLVersionChecker.exe')
-
- with self.prefix(dst="vmp_icons"):
- with self.prefix(src=self.icon_path()):
- self.path("secondlife.ico")
- #VMP Tkinter icons
- with self.prefix(src="vmp_icons"):
- self.path("*.png")
- self.path("*.gif")
-
# Plugin host application
self.path2basename(os.path.join(os.pardir,
'llplugin', 'slplugin', self.args['configuration']),
@@ -765,6 +753,126 @@ class Windows_x86_64_Manifest(ViewerManifest):
return '\n'.join(result)
def package_finish(self):
+ # Check if we should use Velopack instead of NSIS
+ # Note: as of 2026.01's release, we will be building with Velopack's one click install.
+ # We maintain the legacy NSIS packaging mainly for TPVs at this point.
+ if self.args.get('velopack', 'OFF') == 'ON':
+ self.velopack_package_finish()
+ return
+
+ # NSIS packaging (legacy)
+ self.nsis_package_finish()
+
+ def velopack_package_finish(self):
+ # packId determines install folder: %LocalAppData%\{packId}
+ # Uses same naming as NSIS INSTNAME for channel separation
+ pack_id = self.app_name_oneword() # "SecondLife", "SecondLifeBeta", etc.
+ # Velopack requires SemVer2. Use major.minor.patch-buildnumber so that
+ # Velopack can distinguish builds and order them correctly.
+ pack_version = '.'.join(self.args['version'][:3])
+ if len(self.args['version']) > 3 and self.args['version'][3]:
+ pack_version += '-' + self.args['version'][3]
+ pack_title = self.app_name() # Display name with spaces
+ pack_dir = self.get_dst_prefix()
+ main_exe = self.final_exe()
+ installer_base = self.installer_base_name()
+ exclude_pattern = r'.*\.pdb|.*\.map|.*\.bat|.*\.exp|.*\.lib|.*\.nsi|.*\.tar\.xz|secondlife-bin\..*|.*_Setup\.exe|.*-Setup\.exe'
+
+ # Channel-specific icon for the Velopack installer.
+ # CMake copies icons/{channel}/secondlife.ico to res/ll_icon.ico at configure time.
+ # Try the CMake-generated copy first, fall back to the source icon.
+ icon_path = os.path.join(self.get_src_prefix(), 'res', 'll_icon.ico')
+ if not os.path.exists(icon_path):
+ icon_path = os.path.join(self.get_src_prefix(), self.icon_path(), 'secondlife.ico')
+
+ # In CI, defer Velopack packaging to the sign step where Azure credentials
+ # are available. Emit metadata as GitHub outputs so the sign step can run
+ # vpk pack with --signTemplate, producing a package with signed executables.
+ if os.getenv('GITHUB_ACTIONS'):
+ # Copy the icon into pack_dir so it's included in the Windows-app artifact
+ icon_filename = ''
+ if os.path.exists(icon_path):
+ icon_filename = os.path.basename(icon_path)
+ icon_dest = os.path.join(pack_dir, icon_filename)
+ shutil.copy2(icon_path, icon_dest)
+ print("Copied icon %s to %s" % (icon_path, icon_dest))
+ else:
+ print("WARNING: Icon not found at %s" % icon_path)
+
+ # Emit metadata for the sign step
+ self.set_github_output('velopack_pack_id', pack_id)
+ self.set_github_output('velopack_pack_version', pack_version)
+ self.set_github_output('velopack_pack_title', pack_title)
+ self.set_github_output('velopack_main_exe', main_exe)
+ self.set_github_output('velopack_icon', icon_filename)
+ self.set_github_output('velopack_installer_base', installer_base)
+ self.set_github_output('velopack_exclude', exclude_pattern)
+ # Set package_file so llmanifest's touched.bat logic doesn't crash
+ self.package_file = installer_base + '_Setup.exe'
+ print("CI mode: Velopack packaging deferred to sign step")
+ return
+
+ # Local builds: run vpk pack directly (unsigned)
+ vpk_args = [
+ 'vpk', 'pack',
+ '--packId', pack_id,
+ '--packVersion', pack_version,
+ '--packDir', pack_dir,
+ '--mainExe', main_exe,
+ '--packTitle', pack_title,
+ '--exclude', exclude_pattern,
+ # Suppress Velopack's built-in shortcut creation; we create our own
+ # shortcuts in llvelopack.cpp on_after_install hook instead.
+ '--shortcuts', '',
+ ]
+
+ # Add icon — CMake copies the channel-appropriate secondlife.ico to res/ll_icon.ico
+ if os.path.exists(icon_path):
+ print("Using icon: %s" % icon_path)
+ vpk_args.extend(['--icon', icon_path])
+ else:
+ print("WARNING: Icon not found at %s — Setup.exe will have no icon" % icon_path)
+
+ print("Running Velopack packaging: %s" % ' '.join(vpk_args))
+
+ # Run vpk command
+ import subprocess
+ result = subprocess.run(vpk_args, cwd=os.path.dirname(pack_dir), capture_output=True, text=True)
+ if result.stdout:
+ print("vpk stdout: %s" % result.stdout)
+ if result.stderr:
+ print("vpk stderr: %s" % result.stderr)
+ if result.returncode != 0:
+ raise ManifestError("Velopack packaging failed with code %d" % result.returncode)
+
+ # Velopack outputs to a Releases directory
+ releases_dir = os.path.join(os.path.dirname(pack_dir), 'Releases')
+
+ # Move the setup exe INTO pack_dir so it's included in the Windows-app artifact
+ # IMPORTANT: Use hyphen format (-Setup.exe) to avoid the *_Setup.exe exclusion pattern
+ # in viewer_app output (line ~538). The underscore pattern excludes NSIS installers
+ # which are rebuilt during signing, but Velopack installers are created here.
+ # Velopack creates: {packId}-win-Setup.exe
+ velopack_setup = os.path.join(releases_dir, '%s-win-Setup.exe' % pack_id)
+ self.package_file = installer_base + '_Setup.exe'
+ our_setup = os.path.join(pack_dir, self.package_file)
+ if os.path.exists(velopack_setup):
+ shutil.move(velopack_setup, our_setup)
+ print("Moved %s to %s" % (velopack_setup, our_setup))
+
+ # Rename the portable zip to include the version number
+ # Velopack creates: {packId}-win-Portable.zip
+ velopack_portable = os.path.join(releases_dir, '%s-win-Portable.zip' % pack_id)
+ if os.path.exists(velopack_portable):
+ our_portable = os.path.join(releases_dir, installer_base + '_Portable.zip')
+ shutil.move(velopack_portable, our_portable)
+ print("Moved %s to %s" % (velopack_portable, our_portable))
+
+ # Output the Releases directory path for artifact upload (contains nupkg, RELEASES for updates)
+ self.set_github_output('velopack_releases', releases_dir)
+
+ def nsis_package_finish(self):
+ """Package the viewer using NSIS installer (legacy)"""
# a standard map of strings for replacing in the templates
substitution_strings = {
'version' : '.'.join(self.args['version']),
@@ -781,7 +889,7 @@ class Windows_x86_64_Manifest(ViewerManifest):
substitution_strings['installer_file'] = installer_file
version_vars = """
- !define INSTEXE "SLVersionChecker.exe"
+ !define INSTEXE "%(final_exe)s"
!define VERSION "%(version_short)s"
!define VERSION_LONG "%(version)s"
!define VERSION_DASHES "%(version_dashes)s"
@@ -967,15 +1075,6 @@ class Darwin_x86_64_Manifest(ViewerManifest):
with self.prefix(src=self.icon_path(), dst="") :
self.path("secondlife.icns")
- # Copy in the updater script and helper modules
- self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater")
-
- with self.prefix(src="", dst=os.path.join("updater", "icons")):
- self.path2basename(self.icon_path(), "secondlife.ico")
- with self.prefix(src="vmp_icons", dst=""):
- self.path("*.png")
- self.path("*.gif")
-
with self.prefix(src_dst="cursors_mac"):
self.path("*.tif")
@@ -1127,6 +1226,123 @@ class Darwin_x86_64_Manifest(ViewerManifest):
arcname=self.app_name() + ".app")
self.set_github_output_path('viewer_app', tarpath)
+ # Generate Velopack update packages if enabled
+ # This creates the nupkg and RELEASES files needed for auto-updates
+ # Distribution is still via DMG, but updates use Velopack
+ if self.args.get('velopack', 'OFF') == 'ON':
+ self.velopack_package_finish()
+
+ def velopack_package_finish(self):
+ """Generate Velopack update packages for macOS.
+
+ This creates the nupkg and releases.json files needed for auto-updates.
+ Distribution is still via DMG - Velopack only handles the update infrastructure.
+ """
+ # packId determines install identification - same as Windows for consistency
+ pack_id = self.app_name_oneword() # "SecondLife", "SecondLifeBeta", etc.
+ # Velopack requires SemVer2. Use major.minor.patch-buildnumber so that
+ # Velopack can distinguish builds and order them correctly.
+ pack_version = '.'.join(self.args['version'][:3])
+ if len(self.args['version']) > 3 and self.args['version'][3]:
+ pack_version += '-' + self.args['version'][3]
+ pack_title = self.app_name() # Display name with spaces
+
+ # The .app bundle path (e.g., "/path/to/Second Life Release.app")
+ app_bundle = self.get_dst_prefix()
+ # Bundle ID from args (e.g., "com.secondlife.viewer")
+ bundle_id = self.args.get('bundleid', 'com.secondlife.indra.viewer')
+
+ # Icon path for macOS
+ icon_path = os.path.join(self.get_src_prefix(), self.icon_path(), 'secondlife.icns')
+
+ # The main executable inside Contents/MacOS/ is named after the channel
+ main_exe = self.channel()
+
+ # In CI, defer Velopack packaging to the sign step where code signing
+ # credentials are available. Emit metadata as GitHub outputs so the
+ # sign step can run vpk pack after signing the app bundle.
+ if os.getenv('GITHUB_ACTIONS'):
+ self.set_github_output('velopack_mac_pack_id', pack_id)
+ self.set_github_output('velopack_mac_pack_version', pack_version)
+ self.set_github_output('velopack_mac_pack_title', pack_title)
+ self.set_github_output('velopack_mac_main_exe', main_exe)
+ self.set_github_output('velopack_mac_bundle_id', bundle_id)
+ print("CI mode: macOS Velopack packaging deferred to sign step")
+ return
+
+ # Local builds: run vpk pack directly (unsigned)
+
+ # Parent directory containing the .app bundle - this is where we run vpk from
+ # and where the Releases directory will be created
+ work_dir = os.path.dirname(app_bundle)
+
+ # Output directory for releases - clean it first to avoid version conflicts
+ releases_dir = os.path.join(work_dir, 'Releases')
+ if os.path.exists(releases_dir):
+ print("Cleaning existing Releases directory: %s" % releases_dir)
+ shutil.rmtree(releases_dir)
+
+ # Build vpk command for macOS
+ # See: https://docs.velopack.io/reference/cli/content/vpk-osx
+ vpk_args = [
+ 'vpk', 'pack',
+ '--packId', pack_id,
+ '--packVersion', pack_version,
+ '--packDir', app_bundle,
+ '--packTitle', pack_title,
+ '--mainExe', main_exe, # Executable name inside Contents/MacOS/
+ '--bundleId', bundle_id,
+ '--outputDir', releases_dir,
+ '--noInst', # Don't generate .pkg installer - we use DMG for distribution
+ '--verbose', # Show detailed output
+ ]
+
+ # Add icon if exists
+ if os.path.exists(icon_path):
+ vpk_args.extend(['--icon', icon_path])
+
+ print("Running Velopack packaging for macOS:")
+ print(" Command: %s" % ' '.join(vpk_args))
+ print(" Working directory: %s" % work_dir)
+ print(" App bundle: %s" % app_bundle)
+ print(" Main executable: %s" % main_exe)
+
+ # Run vpk command
+ result = subprocess.run(vpk_args, cwd=work_dir, capture_output=True, text=True)
+
+ # Always print output for debugging
+ if result.stdout:
+ print("vpk stdout:\n%s" % result.stdout)
+ if result.stderr:
+ print("vpk stderr:\n%s" % result.stderr)
+
+ if result.returncode != 0:
+ raise ManifestError("Velopack packaging failed with code %d" % result.returncode)
+
+ # Verify the Releases directory was created and contains expected files
+ if not os.path.exists(releases_dir):
+ raise ManifestError("Velopack releases directory not found: %s" % releases_dir)
+
+ # List what was created
+ releases_contents = os.listdir(releases_dir)
+ print("Velopack releases directory contents: %s" % releases_contents)
+
+ # Verify we have the expected files (nupkg and releases JSON)
+ nupkg_files = [f for f in releases_contents if f.endswith('.nupkg')]
+ json_files = [f for f in releases_contents if f.endswith('.json')]
+
+ if not nupkg_files:
+ raise ManifestError("No .nupkg files found in releases directory")
+ if not json_files:
+ raise ManifestError("No releases JSON files found in releases directory")
+
+ print("Generated %d nupkg file(s): %s" % (len(nupkg_files), nupkg_files))
+ print("Generated %d JSON file(s): %s" % (len(json_files), json_files))
+
+ # Output the Releases directory path for artifact upload
+ self.set_github_output('velopack_releases', releases_dir)
+ print("Velopack releases directory: %s" % releases_dir)
+
class LinuxManifest(ViewerManifest):
build_data_json_platform = 'lnx'
@@ -1337,6 +1553,7 @@ if __name__ == "__main__":
dict(name='discord', description="""Indication discord social sdk libraries are needed""", default='OFF'),
dict(name='openal', description="""Indication openal libraries are needed""", default='OFF'),
dict(name='tracy', description="""Indication tracy profiler is enabled""", default='OFF'),
+ dict(name='velopack', description="""Use Velopack installer instead of NSIS""", default='OFF'),
]
try:
main(extra=extra_arguments)
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 37b70964c3..144f807852 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -34,7 +34,6 @@
#include "llcoros.h"
#include "llevents.h"
-#include "lleventfilter.h"
#include "lleventcoro.h"
#include "llexception.h"
#include "stringize.h"
@@ -133,16 +132,6 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
-namespace
-{
-// Instantiate this rendezvous point at namespace scope so it's already
-// present no matter how early the updater might post to it.
-// Use an LLEventMailDrop, which has future-like semantics: regardless of the
-// relative order in which post() or listen() are called, it delivers each
-// post() event to its listener(s) until one of them consumes that event.
-static LLEventMailDrop sSyncPoint("LoginSync");
-}
-
void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{
LLSD printable_params = hidePasswd(login_params);
@@ -225,58 +214,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
}
else
{
- // Synchronize here with the updater. We synchronize here rather
- // than in the fail.login handler, which actually examines the
- // response from login.cgi, because here we are definitely in a
- // coroutine and can definitely use suspendUntilBlah(). Whoever's
- // listening for fail.login might not be.
-
- // If the reason for login failure is that we must install a
- // required update, we definitely want to pass control to the
- // updater to manage that for us. We'll handle any other login
- // failure ourselves, as usual. We figure that no matter where you
- // are in the world, or what kind of network you're on, we can
- // reasonably expect the Viewer Version Manager to respond more or
- // less as quickly as login.cgi. This synchronization is only
- // intended to smooth out minor races between the two services.
- // But what if the updater crashes? Use a timeout so that
- // eventually we'll tire of waiting for it and carry on as usual.
- // Given the above, it can be a fairly short timeout, at least
- // from a human point of view.
-
- // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to
- // consume the posted event.
- LLCoros::OverrideConsuming oc(true);
LLSD responses(mAuthResponse["responses"]);
- LLSD updater;
-
- if (printable_params["wait_for_updater"].asBoolean())
- {
- std::string reason_response = responses["data"]["reason"].asString();
- // Timeout should produce the isUndefined() object passed here.
- if (reason_response == "update")
- {
- LL_INFOS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
- updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
- }
- else
- {
- LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
- updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 3, LLSD());
- }
- if (updater.isUndefined())
- {
- LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
- << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
- }
- }
-
- // Let the fail.login handler deal with empty updater response.
- responses["updater"] = updater;
sendProgressEvent("offline", "fail.login", responses);
}
return; // Done!