diff options
51 files changed, 1730 insertions, 1770 deletions
diff --git a/.github/parameters/setup-macports.yaml b/.github/parameters/setup-macports.yaml new file mode 100644 index 0000000000..ed8cd40acd --- /dev/null +++ b/.github/parameters/setup-macports.yaml @@ -0,0 +1,25 @@ +# Parameters for melusina-org/setup-macports. +# Listing ports here (rather than in a manual `port install` step) means the +# action installs them and they fall under its built-in installation cache, +# which is keyed on the macOS version + this file. Edit this list and the +# cache invalidates automatically. +# +# NOTE: no +universal variants. MacPorts' own guidance is that universal +# builds are poorly supported on Apple Silicon (apr-util fails to build that +# way). The runner is arm64 and we build the viewer arm64-only, so arm64 +# ports are correct and faster. +version: '2.11.5' +ports: + - name: 'cmake' + - name: 'pkgconfig' + - name: 'freealut' + - name: 'apr-util' + - name: 'boost188' + - name: 'glm' + - name: 'hunspell' + - name: 'freetype' + - name: 'minizip' + - name: 'nghttp2' + - name: 'openjpeg' + - name: 'libvorbis' + - name: 'xxhashlib' diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml new file mode 100644 index 0000000000..d1efde8ce9 --- /dev/null +++ b/.github/workflows/build-macos.yml @@ -0,0 +1,123 @@ +name: macOS Build + +on: + pull_request: + branches: [ main ] + push: + tags: + - 'test/*' + - 'build/*' + - 'v*' + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-macos: + name: macOS (arm64) + runs-on: macos-15 + + steps: + - name: Checkout source + uses: actions/checkout@v5 + + - name: Set up MacPorts (installs cached deps from parameter file) + uses: melusina-org/setup-macports@v1 + with: + parameters: .github/parameters/setup-macports.yaml + + - name: Dump MacPorts logs on failure + if: failure() + shell: bash + run: | + echo "=== searching for MacPorts main.log files ===" + LOGDIR="/opt/local/var/macports/logs" + find "$LOGDIR" -name "main.log" 2>/dev/null | while read -r log; do + echo "" + echo "######################################################" + echo "### $log" + echo "######################################################" + tail -n 80 "$log" + done + + - name: Configure + shell: bash + run: | + SDKPATH="$(xcrun --show-sdk-path)" + export LL_BUILD="-O3 -gdwarf-2 -stdlib=libc++ -mmacosx-version-min=12 -iwithsysroot $SDKPATH -std=c++20 -fPIC -DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -DNDEBUG -DPIC -DLL_DARWIN=1" + + mkdir build-macos && cd build-macos + cmake \ + -DCMAKE_BUILD_TYPE:STRING=Release \ + -DADDRESS_SIZE:STRING=64 \ + -DUSE_OPENAL:BOOL=ON \ + -DUSE_FMODSTUDIO:BOOL=OFF \ + -DENABLE_MEDIA_PLUGINS:BOOL=ON \ + -DLL_TESTS:BOOL=OFF \ + -DNDOF:BOOL=OFF \ + -DROOT_PROJECT_NAME:STRING=Megapahit \ + -DVIEWER_CHANNEL:STRING=Megapahit \ + -DVIEWER_BINARY_NAME:STRING=megapahit \ + -DBUILD_SHARED_LIBS:BOOL=OFF \ + -DINSTALL:BOOL=ON \ + -DPACKAGE:BOOL=OFF \ + -DCMAKE_INSTALL_PREFIX:PATH=newview/Megapahit.app/Contents/Resources \ + -DCMAKE_OSX_ARCHITECTURES:STRING=$(uname -m) \ + -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=12 \ + -DENABLE_SIGNING:BOOL=ON \ + -DSIGNING_IDENTITY:STRING=- \ + ../indra + + - name: Build + shell: bash + run: | + cd build-macos + make -j$(sysctl -n hw.ncpu) + + - name: Install into app bundle + shell: bash + run: | + cd build-macos + make install + + - name: Read version + id: version + shell: bash + run: echo "version=$(cat indra/newview/viewer_version.txt)" >> "$GITHUB_OUTPUT" + + - name: Package .app into a .zip + shell: bash + run: | + cd build-macos/newview + ditto -c -k --keepParent "Megapahit.app" \ + "Megapahit-${{ steps.version.outputs.version }}-macos-$(uname -m).zip" + + - name: Verify signature survived packaging + shell: bash + run: | + cd build-macos/newview + mkdir -p verify-tmp + ditto -x -k Megapahit-*-macos-*.zip verify-tmp/ + codesign --verify --deep --strict --verbose=2 verify-tmp/Megapahit.app || { + echo "Signature verification FAILED" + rm -rf verify-tmp + exit 1 + } + rm -rf verify-tmp + echo "Signature verified intact." + + - name: Upload app artifact + uses: actions/upload-artifact@v6 + with: + name: megapahit-macos-${{ steps.version.outputs.version }} + path: build-macos/newview/Megapahit-*-macos-*.zip + if-no-files-found: error + + - name: Upload to release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v3 + with: + name: ${{ github.ref_name }} + files: build-macos/newview/Megapahit-*-macos-*.zip + prerelease: ${{ startsWith(github.ref_name, 'test/') || startsWith(github.ref_name, 'build/') }} diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 0000000000..8be2d33802 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,225 @@ +name: Windows Build + +on: + pull_request: + branches: [ main ] + push: + tags: + - 'test/*' + - 'build/*' + - 'v*' + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-windows-x64: + name: Windows x64 + runs-on: windows-2025-vs2026 + + steps: + - name: Set VCPKG_ROOT + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV" + + - name: Add MSBuild to PATH + uses: microsoft/setup-msbuild@v3 + + - name: Checkout source + uses: actions/checkout@v5 + + - name: Install vcpkg dependencies (x64) + shell: bash + run: | + vcpkg install \ + python3:x64-windows \ + freealut:x64-windows \ + apr-util:x64-windows \ + boost:x64-windows \ + freetype:x64-windows \ + glm:x64-windows \ + hunspell:x64-windows \ + libjpeg-turbo:x64-windows \ + meshoptimizer:x64-windows \ + minizip:x64-windows \ + nanosvg:x64-windows \ + nghttp2:x64-windows \ + openjpeg:x64-windows \ + libvorbis:x64-windows \ + "libxml2[tools]:x64-windows" \ + xxhash:x64-windows + + - name: Configure (x64) + shell: bash + env: + LL_BUILD: "/MD /O2 /Ob2 /std:c++20 /Zc:wchar_t- /Zi /GR /DLL_RELEASE=1 /DLL_RELEASE_FOR_DOWNLOAD=1 /DNDEBUG /D_SECURE_STL=0 /D_HAS_ITERATOR_DEBUGGING=0 /DWIN32 /D_WINDOWS /DLL_WINDOWS=1 /DUNICODE /D_UNICODE /DWINVER=0x0602 /D_WIN32_WINNT=0x0602" + run: | + export PYTHON="$VCPKG_ROOT/installed/x64-windows/tools/python3/python.exe" + CMAKE_BIN=$(find "$VCPKG_ROOT/downloads/tools" -name "cmake.exe" -path "*/x86_64/*" | head -1) + if [ -z "$CMAKE_BIN" ]; then + CMAKE_BIN=cmake + fi + mkdir build-windows-x86_64 + cd build-windows-x86_64 + "$CMAKE_BIN" \ + -DCMAKE_BUILD_TYPE:STRING=Release \ + -DADDRESS_SIZE:STRING=64 \ + -DUSE_OPENAL:BOOL=ON \ + -DUSE_FMODSTUDIO:BOOL=OFF \ + -DENABLE_MEDIA_PLUGINS:BOOL=ON \ + -DLL_TESTS:BOOL=OFF \ + -DNDOF:BOOL=OFF \ + -DROOT_PROJECT_NAME:STRING=Megapahit \ + -DVIEWER_CHANNEL:STRING=Megapahit \ + -DVIEWER_BINARY_NAME:STRING=Megapahit \ + -DBUILD_SHARED_LIBS:BOOL=OFF \ + -DINSTALL:BOOL=ON \ + -DPACKAGE:BOOL=ON \ + "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \ + -DVS_DISABLE_FATAL_WARNINGS:BOOL=ON \ + ../indra + + - name: Build (x64) + shell: bash + run: | + cd build-windows-x86_64 + MSBuild.exe Megapahit.slnx -p:Configuration=Release -m + + - name: Install NSIS (x64) + shell: pwsh + run: | + choco install nsis --no-progress -y + "C:\Program Files (x86)\NSIS" | Out-File -FilePath $env:GITHUB_PATH -Append + + - name: Package (x64) + shell: bash + run: | + cd build-windows-x86_64 + cpack -G NSIS + + - name: Read version + id: version + shell: bash + run: echo "version=$(cat indra/newview/viewer_version.txt)" >> "$GITHUB_OUTPUT" + + - name: Upload installer artifact (x64) + uses: actions/upload-artifact@v6 + with: + name: megapahit-windows-x64-${{ steps.version.outputs.version }} + path: build-windows-x86_64/Megapahit-*-win64.exe + if-no-files-found: error + + - name: Upload to release (x64) + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v3 + with: + name: ${{ github.ref_name }} + files: build-windows-x86_64/Megapahit-*-win64.exe + prerelease: ${{ startsWith(github.ref_name, 'test/') || startsWith(github.ref_name, 'build/') }} + + build-windows-arm64: + name: Windows arm64 + if: false + runs-on: windows-2022 + + steps: + - name: Set VCPKG_ROOT + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV" + + - name: Add MSBuild to PATH + uses: microsoft/setup-msbuild@v3 + + - name: Checkout source + uses: actions/checkout@v5 + + - name: Install vcpkg dependencies (arm64) + shell: bash + run: | + vcpkg install \ + python3:arm64-windows \ + freealut:arm64-windows \ + apr-util:arm64-windows \ + boost:arm64-windows \ + curl:arm64-windows \ + freetype:arm64-windows \ + glm:arm64-windows \ + hunspell:arm64-windows \ + libjpeg-turbo:arm64-windows \ + meshoptimizer:arm64-windows \ + minizip:arm64-windows \ + nanosvg:arm64-windows \ + nghttp2:arm64-windows \ + openjpeg:arm64-windows \ + sse2neon:arm64-windows \ + libvorbis:arm64-windows \ + "libxml2[tools]:arm64-windows" \ + xxhash:arm64-windows + vcpkg install boost-fiber:arm64-windows --allow-unsupported || true + + - name: Configure (arm64) + shell: bash + env: + LL_BUILD: "/MD /O2 /Ob2 /std:c++20 /Zc:wchar_t- /Zi /GR /DLL_RELEASE=1 /DLL_RELEASE_FOR_DOWNLOAD=1 /DNDEBUG /D_SECURE_STL=0 /D_HAS_ITERATOR_DEBUGGING=0 /DWIN32 /D_WINDOWS /DLL_WINDOWS=1 /DUNICODE /D_UNICODE /DWINVER=0x0602 /D_WIN32_WINNT=0x0602 /Zc:preprocessor" + run: | + export PYTHON="$VCPKG_ROOT/installed/arm64-windows/tools/python3/python.exe" + CMAKE_BIN=$(find "$VCPKG_ROOT/downloads/tools" -name "cmake.exe" -path "*/arm64/*" | head -1) + if [ -z "$CMAKE_BIN" ]; then + CMAKE_BIN=$(find "$VCPKG_ROOT/downloads/tools" -name "cmake.exe" | head -1) + fi + if [ -z "$CMAKE_BIN" ]; then + CMAKE_BIN=cmake + fi + mkdir build-windows-aarch64 + cd build-windows-aarch64 + "$CMAKE_BIN" \ + -DCMAKE_BUILD_TYPE:STRING=Release \ + -DADDRESS_SIZE:STRING=64 \ + -DUSE_OPENAL:BOOL=ON \ + -DUSE_FMODSTUDIO:BOOL=OFF \ + -DENABLE_MEDIA_PLUGINS:BOOL=OFF \ + -DLL_TESTS:BOOL=OFF \ + -DNDOF:BOOL=OFF \ + -DROOT_PROJECT_NAME:STRING=Megapahit \ + -DVIEWER_CHANNEL:STRING=Megapahit \ + -DVIEWER_BINARY_NAME:STRING=Megapahit \ + -DBUILD_SHARED_LIBS:BOOL=OFF \ + -DINSTALL:BOOL=ON \ + -DPACKAGE:BOOL=ON \ + "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \ + -DVCPKG_TARGET_TRIPLET:STRING=arm64-windows \ + -DVS_DISABLE_FATAL_WARNINGS:BOOL=ON \ + ../indra + + - name: Build (arm64) + shell: bash + run: | + cd build-windows-aarch64 + MSBuild.exe Megapahit.slnx -p:Configuration=Release -m + + - name: Package (arm64) + shell: bash + run: | + cd build-windows-aarch64 + cpack -G NSIS + + - name: Read version + id: version + shell: bash + run: echo "version=$(cat indra/newview/viewer_version.txt)" >> "$GITHUB_OUTPUT" + + - name: Upload installer artifact (arm64) + uses: actions/upload-artifact@v6 + with: + name: megapahit-windows-arm64-${{ steps.version.outputs.version }} + path: build-windows-aarch64/Megapahit-*-win64.exe + if-no-files-found: error + + - name: Upload to release (arm64) + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v3 + with: + name: ${{ github.ref_name }} + files: build-windows-aarch64/Megapahit-*-win64.exe + prerelease: ${{ startsWith(github.ref_name, 'test/') || startsWith(github.ref_name, 'build/') }} diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml deleted file mode 100644 index 84c05dacdf..0000000000 --- a/.github/workflows/build.yaml +++ /dev/null @@ -1,530 +0,0 @@ -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/*"] - tags: ["Second_Life*"] - -jobs: - # The whole point of the setup job is that we want to set variables once - # that will be consumed by multiple subsequent jobs. - setup: - runs-on: ubuntu-latest - outputs: - release_run: ${{ steps.setvar.outputs.release_run }} - configurations: ${{ steps.setvar.outputs.configurations }} - bugsplat_db: ${{ steps.setvar.outputs.bugsplat_db }} - env: - # Build with a tag like "Second_Life#abcdef0" to generate a release page - # (used for builds we are planning to deploy). - # When you want to use a string variable as a workflow YAML boolean, it's - # important to ensure it's the empty string when false. If you omit || '', - # its value when false is "false", which is interpreted as true. - RELEASE_RUN: ${{ (github.event.inputs.release_run || github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life')) && 'Y' || '' }} - FROM_FORK: ${{ github.event.pull_request.head.repo.fork }} - steps: - - name: Set Variables - id: setvar - shell: bash - run: | - echo "release_run=$RELEASE_RUN" >> "$GITHUB_OUTPUT" - - if [[ "$FROM_FORK" == "true" ]]; then - # PR from fork; don't build with Bugsplat, proprietary libs - echo 'configurations=["ReleaseOS"]' >> $GITHUB_OUTPUT - echo "bugsplat_db=" >> $GITHUB_OUTPUT - else - echo 'configurations=["Release"]' >> $GITHUB_OUTPUT - echo "bugsplat_db=SecondLife_Viewer_2018" >> $GITHUB_OUTPUT - fi - build: - needs: setup - strategy: - matrix: - runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15-xlarge"]') }} - configuration: ${{ fromJson(needs.setup.outputs.configurations) }} - runs-on: ${{ matrix.runner }} - outputs: - viewer_channel: ${{ steps.build.outputs.viewer_channel }} - viewer_version: ${{ steps.build.outputs.viewer_version }} - viewer_branch: ${{ steps.which-branch.outputs.branch }} - 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 }} - AUTOBUILD_CONFIGURATION: ${{ matrix.configuration }} - # authorizes fetching private constituent packages - AUTOBUILD_GITHUB_TOKEN: ${{ secrets.SHARED_AUTOBUILD_GITHUB_TOKEN }} - AUTOBUILD_INSTALLABLE_CACHE: ${{ github.workspace }}/.autobuild-installables - AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables - # Direct autobuild to store vcs_url, vcs_branch and vcs_revision in - # autobuild-package.xml. - AUTOBUILD_VCS_INFO: "true" - AUTOBUILD_VSVER: "170" - DEVELOPER_DIR: "/Applications/Xcode_16.4.app/Contents/Developer" - # Ensure that Linden viewer builds engage Bugsplat. - BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }} - build_coverity: false - build_log_dir: ${{ github.workspace }}/.logs - build_viewer: true - BUILDSCRIPTS_SHARED: ${{ github.workspace }}/.shared - # extracted and committed to viewer repo - BUILDSCRIPTS_SUPPORT_FUNCTIONS: ${{ github.workspace }}/buildscripts_support_functions - GIT_REF: ${{ github.head_ref || github.ref }} - LL_SKIP_REQUIRE_SYSROOT: 1 - # Setting this variable directs Linden's TUT test driver code to capture - # test-program log output at the specified level, but to display it only if - # the individual test fails. - LOGFAIL: DEBUG - master_message_template_checkout: ${{ github.workspace }}/.master-message-template - # 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 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - - - name: Setup python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - name: Checkout build variables - uses: actions/checkout@v6 - with: - repository: secondlife/build-variables - ref: master - path: .build-variables - - - name: Checkout master-message-template - uses: actions/checkout@v6 - with: - repository: secondlife/master-message-template - path: .master-message-template - - - name: Install autobuild and python dependencies - run: pip3 install autobuild llsd - - - name: Cache autobuild packages - id: cache-installables - uses: actions/cache@v5 - with: - path: .autobuild-installables - key: ${{ runner.os }}-64-${{ matrix.configuration }}-${{ hashFiles('autobuild.xml') }} - restore-keys: | - ${{ runner.os }}-64-${{ matrix.configuration }}- - ${{ runner.os }}-64- - - - name: Determine source branch - id: which-branch - uses: secondlife/viewer-build-util/which-branch@v2 - 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 - env: - AUTOBUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }} - RUNNER_OS: ${{ runner.os }} - run: | - # set up things the viewer's build.sh script expects - set -x - mkdir -p "$build_log_dir" - mkdir -p "$BUILDSCRIPTS_SHARED/packages/lib/python" - source "$BUILDSCRIPTS_SUPPORT_FUNCTIONS" - if [[ "$OSTYPE" =~ cygwin|msys ]] - then - native_path() { cygpath --windows "$1"; } - shell_path() { cygpath --unix "$1"; } - else - native_path() { echo "$1"; } - shell_path() { echo "$1"; } - fi - finalize() - { - case "$1" in - true|0) - record_success "Build Succeeded" - ;; - *) - record_failure "Build Failed with $1" - ;; - esac - } - initialize_build() - { - echo "initialize_build" - } - initialize_version() - { - export revision="$AUTOBUILD_BUILD_ID" - } - python_cmd() - { - if [[ "x${1:0:1}" == "x-" ]] # -m, -c, etc. - then # if $1 is a switch, don't try to twiddle paths - "$(shell_path "$PYTHON_COMMAND")" "$@" - elif [[ "$(basename "$1")" == "codeticket.py" ]] - then # ignore any attempt to contact codeticket - echo "## $@" - else # running a script at an explicit path: fix path for Python - local script="$1" - shift - "$(shell_path "$PYTHON_COMMAND")" "$(native_path "$script")" "$@" - fi - } - repo_branch() - { - echo "$AUTOBUILD_VCS_BRANCH" - } - record_dependencies_graph() - { - echo "TODO: generate and post dependency graph" - } - # Since we're not uploading to codeticket, DO NOT sleep for minutes. - sleep() - { - echo "Not sleeping for $1 seconds" - } - export -f native_path shell_path finalize initialize_build initialize_version - export -f python_cmd repo_branch record_dependencies_graph sleep - ## Useful for diagnosing Windows LLProcess/LLLeap test failures - ##export APR_LOG="${RUNNER_TEMP}/apr.log" - export arch=$(uname | cut -b-6) - # Surprise! GH Windows runner's MINGW6 is a $arch value we've never - # seen before, so numerous tests don't know about it. - [[ "$arch" == "MINGW6" ]] && arch=CYGWIN - export AUTOBUILD="$(which autobuild)" - - # determine the viewer channel from the branch or tag name - # trigger an EDU build by including "edu" in the tag - edu=${{ github.ref_type == 'tag' && contains(github.ref_name, 'edu') }} - echo "ref_type=${{ github.ref_type }}, ref_name=${{ github.ref_name }}, edu='$edu'" - branch=$AUTOBUILD_VCS_BRANCH - if [[ "$edu" == "true" ]] - then - export viewer_channel="Second Life Release edu" - elif [[ "$branch" == "develop" ]]; - then - export viewer_channel="Second Life Develop" - else - IFS='/' read -ra ba <<< "$branch" - prefix=${ba[0]} - if [ "$prefix" == "project" ]; then - IFS='_' read -ra prj <<< "${ba[1]}" - prj_str="${prj[*]}" - # uppercase first letter of each word - capitalized=$(echo "$prj_str" | awk '{for (i=1; i<=NF; i++) $i = toupper(substr($i,1,1)) substr($i,2); print}') - export viewer_channel="Second Life Project $capitalized" - elif [[ "$prefix" == "release" || "$prefix" == "main" ]]; - then - export viewer_channel="Second Life Release" - else - export viewer_channel="Second Life Test" - fi - fi - echo "viewer_channel=$viewer_channel" - echo "viewer_channel=$viewer_channel" >> "$GITHUB_OUTPUT" - # On windows we need to point the build to the correct python - # as neither CMake's FindPython nor our custom Python.cmake module - # will resolve the correct interpreter location. - if [[ "$RUNNER_OS" == "Windows" ]]; then - export PYTHON="$(native_path "$(which python)")" - echo "Python location: $PYTHON" - export PYTHON_COMMAND="$PYTHON" - else - export PYTHON_COMMAND="python3" - fi - export PYTHON_COMMAND_NATIVE="$(native_path "$PYTHON_COMMAND")" - - ./build.sh - - # Each artifact is downloaded as a distinct .zip file. Multiple jobs - # (per the matrix above) writing the same filepath to the same - # artifact name will *overwrite* that file. Moreover, they can - # interfere with each other, causing the upload to fail. - # https://github.com/actions/upload-artifact#uploading-to-the-same-artifact - # Given the size of our installers, and the fact that we typically - # only want to download just one instead of a single zip containing - # several, generate a distinct artifact name for each installer. - # If the matrix above can run multiple builds on the same - # platform, we must disambiguate on more than the platform name. - # e.g. if we were still running Windows 32-bit builds, we'd need to - # qualify the artifact with bit width. - if [[ "$AUTOBUILD_CONFIGURATION" == "ReleaseOS" ]] - then cfg_suffix='OS' - else cfg_suffix='' - fi - echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT - - - name: Upload executable - if: steps.build.outputs.viewer_app - uses: actions/upload-artifact@v6 - with: - name: "${{ steps.build.outputs.artifact }}-app" - path: | - ${{ steps.build.outputs.viewer_app }} - - # The other upload of nontrivial size is the symbol file. Use a distinct - # artifact for that too. - - name: Upload symbol file - if: steps.build.outputs.symbolfile - uses: actions/upload-artifact@v6 - with: - name: "${{ steps.build.outputs.artifact }}-symbols" - path: ${{ steps.build.outputs.symbolfile }} - - - name: Upload metadata - uses: actions/upload-artifact@v6 - with: - name: "${{ steps.build.outputs.artifact }}-metadata" - # emitted by build.sh, possibly multiple lines - path: | - ${{ steps.build.outputs.metadata }} - - - name: Upload physics package - uses: actions/upload-artifact@v6 - # should only be set for viewer-private - if: matrix.configuration == 'Release' && steps.build.outputs.physicstpv - with: - name: "${{ steps.build.outputs.artifact }}-physics" - # emitted by build.sh, zero or one lines - path: | - ${{ steps.build.outputs.physicstpv }} - - sign-and-package-windows: - env: - AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} - AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - needs: build - runs-on: windows-2022 - 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.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: - NOTARIZE_CREDS_MACOS: ${{ secrets.NOTARIZE_CREDS_MACOS }} - SIGNING_CERT_MACOS: ${{ secrets.SIGNING_CERT_MACOS }} - SIGNING_CERT_MACOS_IDENTITY: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }} - SIGNING_CERT_MACOS_PASSWORD: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }} - needs: build - runs-on: macos-latest - steps: - - name: Unpack Mac notarization credentials - if: env.NOTARIZE_CREDS_MACOS - id: note-creds - shell: bash - run: | - # In NOTARIZE_CREDS_MACOS we expect to find: - # USERNAME="..." - # PASSWORD="..." - # TEAM_ID="..." - eval "${{ env.NOTARIZE_CREDS_MACOS }}" - echo "::add-mask::$USERNAME" - echo "::add-mask::$PASSWORD" - echo "::add-mask::$TEAM_ID" - echo "note_user=$USERNAME" >> "$GITHUB_OUTPUT" - echo "note_pass=$PASSWORD" >> "$GITHUB_OUTPUT" - echo "note_team=$TEAM_ID" >> "$GITHUB_OUTPUT" - # If we didn't manage to retrieve all of these credentials, better - # find out sooner than later. - [[ -n "$USERNAME" && -n "$PASSWORD" && -n "$TEAM_ID" ]] - - - 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.1.0 - with: - channel: ${{ needs.build.outputs.viewer_channel }} - imagename: ${{ needs.build.outputs.imagename }} - cert_base64: ${{ env.SIGNING_CERT_MACOS }} - cert_name: ${{ env.SIGNING_CERT_MACOS_IDENTITY }} - cert_pass: ${{ env.SIGNING_CERT_MACOS_PASSWORD }} - 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: - BUGSPLAT_DATABASE: "${{ secrets.BUGSPLAT_DATABASE }}" - SYMBOL_UPLOAD_CLIENT_ID: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_ID }}" - SYMBOL_UPLOAD_CLIENT_SECRET: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_SECRET }}" - needs: build - if: needs.build.outputs.configuration == 'Release' - runs-on: ubuntu-latest - steps: - - name: Download viewer exe - uses: actions/download-artifact@v7 - with: - name: Windows-app - path: _artifacts - - name: Download Windows Symbols - if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - uses: actions/download-artifact@v7 - with: - name: Windows-symbols - - name: Extract viewer pdb - if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - shell: bash - run: | - tar -xJf "${{ needs.build.outputs.viewer_channel }}.sym.tar.xz" -C _artifacts - - name: Post Windows symbols - if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - uses: BugSplat-Git/symbol-upload@095d163ae9ceb006d286a731dcd35cf6a1b458c8 - with: - clientId: "${{ env.SYMBOL_UPLOAD_CLIENT_ID }}" - clientSecret: "${{ env.SYMBOL_UPLOAD_CLIENT_SECRET }}" - database: "${{ env.BUGSPLAT_DATABASE }}" - application: ${{ needs.build.outputs.viewer_channel }} - version: ${{ needs.build.outputs.viewer_version }} - directory: _artifacts - files: "**/{SecondLifeViewer.exe,llwebrtc.dll,*.pdb}" - node-version: "22" - dumpSyms: false - - post-mac-symbols: - env: - BUGSPLAT_DATABASE: "${{ secrets.BUGSPLAT_DATABASE }}" - SYMBOL_UPLOAD_CLIENT_ID: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_ID }}" - SYMBOL_UPLOAD_CLIENT_SECRET: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_SECRET }}" - needs: build - if: needs.build.outputs.configuration == 'Release' - runs-on: ubuntu-latest - steps: - - name: Download Mac Symbols - if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - uses: actions/download-artifact@v7 - with: - name: macOS-symbols - - name: Post Mac symbols - if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID - uses: BugSplat-Git/symbol-upload@095d163ae9ceb006d286a731dcd35cf6a1b458c8 - with: - clientId: "${{ env.SYMBOL_UPLOAD_CLIENT_ID }}" - clientSecret: "${{ env.SYMBOL_UPLOAD_CLIENT_SECRET }}" - database: "${{ env.BUGSPLAT_DATABASE }}" - application: ${{ needs.build.outputs.viewer_channel }} - version: ${{ needs.build.outputs.viewer_version }} (${{ needs.build.outputs.viewer_version }}) - directory: . - files: "**/*.xcarchive.zip" - node-version: "22" - dumpSyms: false - - release: - needs: [setup, build, sign-and-package-windows, sign-and-package-mac] - runs-on: ubuntu-latest - if: needs.setup.outputs.release_run - steps: - - uses: actions/download-artifact@v7 - with: - pattern: "*-installer" - - - uses: actions/download-artifact@v7 - with: - pattern: "*-metadata" - - - uses: actions/download-artifact@v4 - with: - pattern: "*-releases" - - - name: Rename metadata - run: | - cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml - cp Windows-metadata/newview/viewer_version.txt Windows-viewer_version.txt - cp macOS-metadata/autobuild-package.xml macOS-autobuild-package.xml - cp macOS-metadata/newview/viewer_version.txt macOS-viewer_version.txt - - # forked from softprops/action-gh-release - - name: Create GitHub release - id: release - uses: secondlife-3p/action-gh-release@v1 - with: - # name the release page for the branch - name: "${{ needs.build.outputs.viewer_branch }}" - # SL-20546: want the channel and version to be visible on the - # release page - body: | - Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - ${{ needs.build.outputs.viewer_channel }} - ${{ needs.build.outputs.viewer_version }} - ${{ needs.build.outputs.relnotes }} - prerelease: true - generate_release_notes: true - target_commitish: ${{ github.sha }} - append_body: true - fail_on_unmatched_files: false - files: | - macOS-installer/*.dmg - Windows-installer/*.exe - *-autobuild-package.xml - *-viewer_version.txt - Windows-releases/* - macOS-releases/* - - - name: post release URL - run: | - echo "::notice::Release ${{ steps.release.outputs.url }}" diff --git a/.github/workflows/check-pr.yaml b/.github/workflows/check-pr.yaml deleted file mode 100644 index 08e907e83f..0000000000 --- a/.github/workflows/check-pr.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: Check PR - -on: - pull_request: - types: [opened, edited, reopened, synchronize] - -permissions: - contents: read - -jobs: - check-description: - runs-on: ubuntu-latest - steps: - - name: Check PR description - uses: actions/github-script@v8 - with: - script: | - const description = context.payload.pull_request.body || ''; - if (description.trim().length < 20) { - core.setFailed("❌ PR description is too short. Please provide at least 20 characters."); - } diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml deleted file mode 100644 index 800f3c42d1..0000000000 --- a/.github/workflows/cla.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Check CLA - -on: - issue_comment: - types: [created] - pull_request_target: - types: [opened, closed, synchronize] - -jobs: - cla: - name: Check CLA - runs-on: ubuntu-latest - steps: - - name: CLA Assistant - if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - uses: secondlife-3p/contributor-assistant@v2.6.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PERSONAL_ACCESS_TOKEN: ${{ secrets.SHARED_CLA_TOKEN }} - with: - branch: main - path-to-document: https://github.com/secondlife/cla/blob/main/CLA.md - path-to-signatures: signatures.json - remote-organization-name: secondlife - remote-repository-name: cla-signatures - allowlist: callum@mbp.localdomain,rye@lindenlab.com,rye,signal@lindenlab.com,dependabot*,bot* diff --git a/.github/workflows/label.yaml b/.github/workflows/label.yaml deleted file mode 100644 index 218327ef47..0000000000 --- a/.github/workflows/label.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: Pull Request Labeler -on: - - pull_request_target - -jobs: - triage: - permissions: - contents: read - pull-requests: write - runs-on: ubuntu-latest - steps: - - uses: actions/labeler@v6 - with: - configuration-path: .github/labeler.yaml - repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml deleted file mode 100644 index 93bcafdea8..0000000000 --- a/.github/workflows/pre-commit.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: pre-commit - -on: - pull_request: - push: - branches: [main, contribute] - tags: [v*] - - -jobs: - pre-commit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 - with: - python-version: 3.x - - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml deleted file mode 100644 index b6883d88d4..0000000000 --- a/.github/workflows/qatest.yaml +++ /dev/null @@ -1,610 +0,0 @@ -name: Run QA Test # Runs automated tests on self-hosted QA machines - -permissions: - contents: read - -on: - workflow_run: - workflows: ["Build"] - types: - - completed - workflow_dispatch: - inputs: - build_id: - description: 'Build workflow run ID (e.g. For github.com/secondlife/viewer/actions/runs/1234567890 the ID is 1234567890)' - required: true - default: '14806728332' - -jobs: - debug-workflow: - runs-on: ubuntu-latest - steps: - - name: Debug Workflow Variables - run: | - echo "Workflow Conclusion: ${{ github.event.workflow_run.conclusion }}" - echo "Workflow Head Branch: ${{ github.event.workflow_run.head_branch }}" - echo "Workflow Run ID: ${{ github.event.workflow_run.id }}" - echo "Head Commit Message: ${{ github.event.workflow_run.head_commit.message }}" - echo "GitHub Ref: ${{ github.ref }}" - echo "GitHub Ref Name: ${{ github.ref_name }}" - echo "GitHub Event Name: ${{ github.event_name }}" - echo "GitHub Workflow Name: ${{ github.workflow }}" - - install-viewer-and-run-tests: - concurrency: - group: ${{ github.workflow }}-${{ matrix.runner }} - cancel-in-progress: false # Prevents cancellation of in-progress jobs - - strategy: - matrix: - include: - - os: windows - runner: qa-windows-atlas - artifact: Windows-installer - install-path: 'C:\viewer-automation-main' - - os: windows - runner: qa-windows-asus-dan - artifact: Windows-installer - install-path: 'C:\viewer-automation-main' - - os: windows - runner: qa-windows-kurt - artifact: Windows-installer - install-path: 'C:\viewer-automation-main' - - os: mac - runner: qa-mac-dan - artifact: macOS-installer - install-path: '$HOME/Documents/viewer-automation' - - os: mac - runner: qa-mac-atlas - artifact: macOS-installer - install-path: '$HOME/Documents/viewer-automation' - - os: mac - runner: qa-mac-caleb - artifact: macOS-installer - install-path: '$HOME/Documents/viewer-automation' - fail-fast: false - - runs-on: [self-hosted, "${{ matrix.runner }}"] - # Run test only on successful builds of Second_Life_X branches or on manual dispatch - if: > - (github.event_name == 'workflow_run' && - github.event.workflow_run.conclusion == 'success' && - startsWith(github.event.workflow_run.head_branch, 'Second_Life')) || - github.event_name == 'workflow_dispatch' - - steps: - # Windows-specific steps - - name: Set Build ID - if: matrix.os == 'windows' - shell: pwsh - run: | - if ("${{ github.event_name }}" -eq "workflow_dispatch") { - echo "BUILD_ID=${{ github.event.inputs.build_id }}" | Out-File -FilePath $env:GITHUB_ENV -Append - echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.inputs.build_id }}/artifacts" | Out-File -FilePath $env:GITHUB_ENV -Append - } else { - echo "BUILD_ID=${{ github.event.workflow_run.id }}" | Out-File -FilePath $env:GITHUB_ENV -Append - echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.workflow_run.id }}/artifacts" | Out-File -FilePath $env:GITHUB_ENV -Append - } - - - name: Temporarily Allow PowerShell Scripts (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - Set-ExecutionPolicy RemoteSigned -Scope Process -Force - - - name: Verify viewer-automation-main Exists (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - if (-Not (Test-Path -Path '${{ matrix.install-path }}')) { - Write-Host '❌ Error: viewer-automation folder not found on runner!' - exit 1 - } - Write-Host '✅ viewer-automation folder is provided.' - - - name: Verify viewer-automation-main is Up-To-Date (Windows) - if: matrix.os == 'windows' - shell: pwsh - continue-on-error: true - run: | - cd ${{ matrix.install-path }} - Write-Host "Checking for repository updates..." - - # Check if .git directory exists - if (Test-Path -Path ".git") { - try { - # Save local changes instead of discarding them - git stash push -m "Automated stash before update $(Get-Date)" - Write-Host "Local changes saved (if any)" - - # Update the repository - git pull - Write-Host "✅ Repository updated successfully" - - # Try to restore local changes if any were stashed - $stashList = git stash list - if ($stashList -match "Automated stash before update") { - try { - git stash pop - Write-Host "✅ Local changes restored successfully" - } catch { - Write-Host "⚠️ Conflict when restoring local changes" - # Save the conflicted state in a new branch for later review - $branchName = "conflict-recovery-$(Get-Date -Format 'yyyyMMdd-HHmmss')" - git checkout -b $branchName - Write-Host "✅ Created branch '$branchName' with conflicted state" - - # For test execution, revert to a clean state - git reset --hard HEAD - Write-Host "✅ Reset to clean state for test execution" - } - } - } catch { - Write-Host "⚠️ Could not update repository: $_" - Write-Host "Continuing with existing files..." - } - } else { - Write-Host "⚠️ Not a Git repository, using existing files" - } - - - name: Verify Python Installation (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - try { - $pythonVersion = (python --version) - Write-Host "✅ Python found: $pythonVersion" - } catch { - Write-Host "❌ Error: Python not found in PATH. Please install Python on this runner." - exit 1 - } - - - name: Setup Python Virtual Environment (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force - cd ${{ matrix.install-path }} - - if (-Not (Test-Path -Path ".venv")) { - Write-Host "Creating virtual environment..." - python -m venv .venv - } else { - Write-Host "Using existing virtual environment" - } - - # Direct environment activation to avoid script execution issues - $env:VIRTUAL_ENV = "$PWD\.venv" - $env:PATH = "$env:VIRTUAL_ENV\Scripts;$env:PATH" - - # Install dependencies - if (Test-Path -Path "requirements.txt") { - Write-Host "Installing dependencies from requirements.txt..." - pip install -r requirements.txt - - # Install Playwright browsers - add this line - Write-Host "Installing Playwright browsers..." - python -m playwright install - } else { - pip install outleap requests behave playwright - # Install Playwright browsers - add this line - Write-Host "Installing Playwright browsers..." - python -m playwright install - } - - - name: Fetch & Download Installer Artifact (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - $BUILD_ID = "${{ env.BUILD_ID }}" - $ARTIFACTS_URL = "${{ env.ARTIFACTS_URL }}" - - # Fetch the correct artifact URL - $response = Invoke-RestMethod -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}" } -Uri $ARTIFACTS_URL - $ARTIFACT_NAME = ($response.artifacts | Where-Object { $_.name -eq "${{ matrix.artifact }}" }).archive_download_url - - if (-Not $ARTIFACT_NAME) { - Write-Host "❌ Error: ${{ matrix.artifact }} artifact not found!" - exit 1 - } - - Write-Host "✅ Artifact found: $ARTIFACT_NAME" - - # Secure download path - $DownloadPath = "$env:TEMP\secondlife-build-$BUILD_ID" - New-Item -ItemType Directory -Path $DownloadPath -Force | Out-Null - $InstallerPath = "$DownloadPath\installer.zip" - - # Download the ZIP - Invoke-WebRequest -Uri $ARTIFACT_NAME -Headers @{Authorization="token ${{ secrets.GITHUB_TOKEN }}"} -OutFile $InstallerPath - - # Ensure download succeeded - if (-Not (Test-Path $InstallerPath)) { - Write-Host "❌ Error: Failed to download ${{ matrix.artifact }}.zip" - exit 1 - } - - # Set the path for other steps - echo "DOWNLOAD_PATH=$DownloadPath" | Out-File -FilePath $env:GITHUB_ENV -Append - - - name: Extract Installer & Locate Executable (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - $BUILD_ID = "${{ env.BUILD_ID }}" - $ExtractPath = "${{ env.DOWNLOAD_PATH }}" - $InstallerZip = "$ExtractPath\installer.zip" - - # Print paths for debugging - Write-Host "Extract Path: $ExtractPath" - Write-Host "Installer ZIP Path: $InstallerZip" - - # Verify ZIP exists before extracting - if (-Not (Test-Path $InstallerZip)) { - Write-Host "❌ Error: ZIP file not found at $InstallerZip!" - exit 1 - } - - Write-Host "✅ ZIP file exists and is valid. Extracting..." - - Expand-Archive -Path $InstallerZip -DestinationPath $ExtractPath -Force - - # Find installer executable - $INSTALLER_PATH = (Get-ChildItem -Path $ExtractPath -Filter '*.exe' -Recurse | Select-Object -First 1).FullName - - if (-Not $INSTALLER_PATH -or $INSTALLER_PATH -eq "") { - Write-Host "❌ Error: No installer executable found in the extracted files!" - Write-Host "📂 Extracted Files:" - Get-ChildItem -Path $ExtractPath -Recurse | Format-Table -AutoSize - exit 1 - } - - Write-Host "✅ Installer found: $INSTALLER_PATH" - echo "INSTALLER_PATH=$INSTALLER_PATH" | Out-File -FilePath $env:GITHUB_ENV -Append - - - name: Install Second Life (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - # Windows - Use Task Scheduler to bypass UAC - $action = New-ScheduledTaskAction -Execute "${{ env.INSTALLER_PATH }}" -Argument "/S" - $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest - $task = New-ScheduledTask -Action $action -Principal $principal - Register-ScheduledTask -TaskName "SilentSLInstaller" -InputObject $task -Force - Start-ScheduledTask -TaskName "SilentSLInstaller" - - - name: Wait for Installation to Complete (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - Write-Host "Waiting for the Second Life installer to finish..." - do { - Start-Sleep -Seconds 5 - $installerProcess = Get-Process | Where-Object { $_.Path -eq "${{ env.INSTALLER_PATH }}" } - } while ($installerProcess) - - Write-Host "✅ Installation completed!" - - - name: Cleanup After Installation (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - # Cleanup Task Scheduler Entry - Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false - Write-Host "✅ Task Scheduler entry removed." - - # Delete Installer ZIP - $DeletePath = "${{ env.DOWNLOAD_PATH }}\installer.zip" - - Write-Host "Checking if installer ZIP exists: $DeletePath" - - # Ensure the ZIP file exists before trying to delete it - if (Test-Path $DeletePath) { - Remove-Item -Path $DeletePath -Force - Write-Host "✅ Successfully deleted: $DeletePath" - } else { - Write-Host "⚠️ Warning: ZIP file does not exist, skipping deletion." - } - - - name: Run QA Test Script (Windows) - if: matrix.os == 'windows' - shell: pwsh - run: | - Write-Host "Running QA Test script on Windows runner: ${{ matrix.runner }}..." - cd ${{ matrix.install-path }} - - # Activate virtual environment - Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force - $env:VIRTUAL_ENV = "$PWD\.venv" - $env:PATH = "$env:VIRTUAL_ENV\Scripts;$env:PATH" - - # Set runner name as environment variable - $env:RUNNER_NAME = "${{ matrix.runner }}" - - # Run the test script - python runTests.py - - # Mac-specific steps - - name: Set Build ID (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "BUILD_ID=${{ github.event.inputs.build_id }}" >> $GITHUB_ENV - echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.inputs.build_id }}/artifacts" >> $GITHUB_ENV - else - echo "BUILD_ID=${{ github.event.workflow_run.id }}" >> $GITHUB_ENV - echo "ARTIFACTS_URL=https://api.github.com/repos/secondlife/viewer/actions/runs/${{ github.event.workflow_run.id }}/artifacts" >> $GITHUB_ENV - fi - - - name: Verify viewer-automation-main Exists (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - if [ ! -d "${{ matrix.install-path }}" ]; then - echo "❌ Error: viewer-automation folder not found on runner!" - exit 1 - fi - echo "✅ viewer-automation is provided." - - - name: Verify viewer-automation-main is Up-To-Date (Mac) - if: matrix.os == 'mac' - shell: bash - continue-on-error: true - run: | - cd ${{ matrix.install-path }} - echo "Checking for repository updates..." - - # Check if .git directory exists - if [ -d ".git" ]; then - # Save local changes instead of discarding them - git stash push -m "Automated stash before update $(date)" - echo "Local changes saved (if any)" - - # Update the repository - git pull || echo "⚠️ Could not update repository" - echo "✅ Repository updated (or attempted update)" - - # Try to restore local changes if any were stashed - if git stash list | grep -q "Automated stash before update"; then - # Try to pop the stash, but be prepared for conflicts - if ! git stash pop; then - echo "⚠️ Conflict when restoring local changes" - # Save the conflicted state in a new branch for later review - branch_name="conflict-recovery-$(date +%Y%m%d-%H%M%S)" - git checkout -b "$branch_name" - echo "✅ Created branch '$branch_name' with conflicted state" - - # For test execution, revert to a clean state - git reset --hard HEAD - echo "✅ Reset to clean state for test execution" - else - echo "✅ Local changes restored successfully" - fi - fi - else - echo "⚠️ Not a Git repository, using existing files" - fi - - - name: Verify Python Installation (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - if command -v python3 &> /dev/null; then - PYTHON_VERSION=$(python3 --version) - echo "✅ Python found: $PYTHON_VERSION" - else - echo "❌ Error: Python3 not found in PATH. Please install Python on this runner." - exit 1 - fi - - - name: Setup Python Virtual Environment (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - cd ${{ matrix.install-path }} - - # Create virtual environment if it doesn't exist - if [ ! -d ".venv" ]; then - echo "Creating virtual environment..." - python3 -m venv .venv - else - echo "Using existing virtual environment" - fi - - # Activate virtual environment - source .venv/bin/activate - - # Install dependencies - if [ -f "requirements.txt" ]; then - pip install -r requirements.txt - echo "✅ Installed dependencies from requirements.txt" - - # Install Playwright browsers - add this line - echo "Installing Playwright browsers..." - python -m playwright install - else - pip install outleap requests behave playwright - echo "⚠️ requirements.txt not found, installed basic dependencies" - - # Install Playwright browsers - add this line - echo "Installing Playwright browsers..." - python -m playwright install - fi - - - name: Fetch & Download Installer Artifact (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - # Mac-specific Bash commands - response=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s ${{ env.ARTIFACTS_URL }}) - ARTIFACT_NAME=$(echo $response | jq -r '.artifacts[] | select(.name=="${{ matrix.artifact }}") | .archive_download_url') - - if [ -z "$ARTIFACT_NAME" ]; then - echo "❌ Error: ${{ matrix.artifact }} artifact not found!" - exit 1 - fi - - echo "✅ Artifact found: $ARTIFACT_NAME" - - # Secure download path - DOWNLOAD_PATH="/tmp/secondlife-build-${{ env.BUILD_ID }}" - mkdir -p $DOWNLOAD_PATH - INSTALLER_PATH="$DOWNLOAD_PATH/installer.zip" - - # Download the ZIP - curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -L $ARTIFACT_NAME -o $INSTALLER_PATH - - # Ensure download succeeded - if [ ! -f "$INSTALLER_PATH" ]; then - echo "❌ Error: Failed to download ${{ matrix.artifact }}.zip" - exit 1 - fi - - # Set the path for other steps - echo "DOWNLOAD_PATH=$DOWNLOAD_PATH" >> $GITHUB_ENV - - - name: Extract Installer & Locate Executable (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - EXTRACT_PATH="${{ env.DOWNLOAD_PATH }}" - INSTALLER_ZIP="$EXTRACT_PATH/installer.zip" - - # Debug output - echo "Extract Path: $EXTRACT_PATH" - echo "Installer ZIP Path: $INSTALLER_ZIP" - - # Verify ZIP exists - if [ ! -f "$INSTALLER_ZIP" ]; then - echo "❌ Error: ZIP file not found at $INSTALLER_ZIP!" - exit 1 - fi - - echo "✅ ZIP file exists and is valid. Extracting..." - - # Extract the ZIP - unzip -o "$INSTALLER_ZIP" -d "$EXTRACT_PATH" - - # Find DMG file - INSTALLER_PATH=$(find "$EXTRACT_PATH" -name "*.dmg" -type f | head -1) - - if [ -z "$INSTALLER_PATH" ]; then - echo "❌ Error: No installer DMG found in the extracted files!" - echo "📂 Extracted Files:" - ls -la "$EXTRACT_PATH" - exit 1 - fi - - echo "✅ Installer found: $INSTALLER_PATH" - echo "INSTALLER_PATH=$INSTALLER_PATH" >> $GITHUB_ENV - - - name: Install Second Life (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - # Mac installation - echo "Mounting DMG installer..." - MOUNT_POINT="/tmp/secondlife-dmg" - mkdir -p "$MOUNT_POINT" - - # Mount the DMG - hdiutil attach "$INSTALLER_PATH" -mountpoint "$MOUNT_POINT" -nobrowse - - echo "✅ DMG mounted at $MOUNT_POINT" - - echo "Installing application to default location from DMG..." - - # Find the .app bundle in the DMG - APP_PATH=$(find "$MOUNT_POINT" -name "*.app" -type d | head -1) - - if [ -z "$APP_PATH" ]; then - echo "❌ Error: No .app bundle found in the mounted DMG!" - exit 1 - fi - - APP_NAME=$(basename "$APP_PATH") - DEST_PATH="/Applications/$APP_NAME" - - # Handle existing installation - if [ -d "$DEST_PATH" ]; then - echo "Found existing installation at: $DEST_PATH" - echo "Moving existing installation to trash..." - - # Move to trash instead of force removing - TRASH_PATH="$HOME/.Trash/$(date +%Y%m%d_%H%M%S)_$APP_NAME" - mv "$DEST_PATH" "$TRASH_PATH" || { - echo "⚠️ Could not move to trash, trying direct removal..." - rm -rf "$DEST_PATH" || { - echo "❌ Could not remove existing installation" - echo "Please manually remove: $DEST_PATH" - exit 1 - } - } - - echo "✅ Existing installation handled successfully" - fi - - # Copy the .app to /Applications - echo "Copying app from: $APP_PATH" - echo "To destination: /Applications/" - cp -R "$APP_PATH" /Applications/ - - # Verify the app was copied successfully - if [ ! -d "$DEST_PATH" ]; then - echo "❌ Error: Failed to install application to /Applications!" - exit 1 - fi - - echo "✅ Application installed successfully to /Applications" - - # Save mount point for cleanup - echo "MOUNT_POINT=$MOUNT_POINT" >> $GITHUB_ENV - - - name: Wait for Installation to Complete (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - echo "Waiting for installation to complete..." - # Sleep to allow installation to finish (adjust as needed) - sleep 30 - echo "✅ Installation completed" - - - name: Cleanup After Installation (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - # Mac cleanup - # Unmount the DMG - echo "Unmounting DMG..." - hdiutil detach "${{ env.MOUNT_POINT }}" -force - - # Clean up temporary files - echo "Cleaning up temporary files..." - rm -rf "${{ env.DOWNLOAD_PATH }}" - rm -rf "${{ env.MOUNT_POINT }}" - - echo "✅ Cleanup completed" - - - name: Run QA Test Script (Mac) - if: matrix.os == 'mac' - shell: bash - run: | - echo "Running QA Test script on Mac runner: ${{ matrix.runner }}..." - cd ${{ matrix.install-path }} - - # Activate virtual environment - source .venv/bin/activate - - # Set runner name as environment variable - export RUNNER_NAME="${{ matrix.runner }}" - - # Run the test script - python runTests.py - - # - name: Upload Test Results - # if: always() - # uses: actions/upload-artifact@v4 - # with: - # name: test-results-${{ matrix.runner }} - # path: ${{ matrix.install-path }}/regressionTest/test_results.html diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml deleted file mode 100644 index edfe71b693..0000000000 --- a/.github/workflows/stale.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: Stale PRs -on: - workflow_dispatch: - schedule: - - cron: 0 0 * * * - -permissions: - issues: write - pull-requests: write - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v10 - id: stale - with: - stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days - days-before-stale: 30 - days-before-close: 7 - days-before-issue-close: -1 - exempt-pr-labels: blocked,must,should,keep - stale-pr-label: stale - - name: Print outputs - run: echo ${{ join(steps.stale.outputs.*, ',') }} diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml deleted file mode 100644 index 0f826222a0..0000000000 --- a/.github/workflows/tag-release.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: Tag a Build - -on: - # schedule event triggers always run on the default branch - # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule - schedule: - # run "nightly" builds on default branch every mon/wed/fri - - cron: "21 2 * * 2,4,6" # 2:21am UTC tues/thurs/sat == 7:21pm PDT mon/wed/fri -- see https://crontab.guru/#21_01_*_*_2,4,6 - workflow_dispatch: - inputs: - channel: - description: "Channel to configure the build" - required: true - type: choice - default: "Test" - options: - - "Test" - - "Develop" - - "Project" - - "Release" - project: - description: "Project Name (used for channel name in project builds, and tag name for all builds)" - default: "hippo" - tag_override: - description: "Override the tag name (optional). If the tag already exists, a numeric suffix is appended." - required: false - -jobs: - tag-release: - runs-on: ubuntu-latest - steps: - - name: Setup Env Vars - run: | - CHANNEL="${{ inputs.channel }}" - echo VIEWER_CHANNEL="Second_Life_${CHANNEL:-Develop}" >> ${GITHUB_ENV} - 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: Create Tag - uses: actions/github-script@v8 - with: - # use a real access token instead of GITHUB_TOKEN default. - # required so that the results of this tag creation can trigger the build workflow - # https://stackoverflow.com/a/71372524 - # https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow - # this token will need to be renewed anually in January - github-token: ${{ secrets.LL_TAG_RELEASE_TOKEN }} - script: | - 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; - } - } - } @@ -19,7 +19,7 @@ $ cd build-`uname -s|tr '[:upper:]' '[:lower:]'`-`uname -m` ### Arch ``` -$ sudo pacman -S cmake base-devel python freealut apr-util boost fltk glm glu hunspell minizip nanosvg libnghttp2 openjpeg2 libpipewire sdl2 vlc libvorbis xxhash +$ sudo pacman -S cmake base-devel patchelf python freealut apr-util boost cef fltk glm glu hunspell minizip nanosvg libnghttp2 openjpeg2 libpipewire sdl2 vlc libvorbis xxhash $ export LL_BUILD="-O3 -std=c++20 -fPIC -DLL_LINUX=1" $ cmake -DCMAKE_BUILD_TYPE:STRING=Release -DADDRESS_SIZE:STRING=64 -DUSE_OPENAL:BOOL=ON -DUSE_FMODSTUDIO:BOOL=OFF -DENABLE_MEDIA_PLUGINS:BOOL=ON -DLL_TESTS:BOOL=OFF -DNDOF:BOOL=ON -DROOT_PROJECT_NAME:STRING=Megapahit -DVIEWER_CHANNEL:STRING=Megapahit -DVIEWER_BINARY_NAME:STRING=megapahit -DBUILD_SHARED_LIBS:BOOL=OFF -DINSTALL:BOOL=ON -DPACKAGE:BOOL=ON -DCMAKE_INSTALL_PREFIX=/usr ../indra $ make -j`nproc` @@ -31,7 +31,7 @@ $ megapahit ### Debian amd64 ``` -$ sudo apt install cmake pkg-config libxml2-utils libalut-dev libaprutil1-dev libboost-fiber-dev libboost-json-dev libboost-program-options-dev libboost-regex-dev libboost-url-dev libexpat1-dev libfltk1.4-dev libfontconfig-dev libfreetype-dev libglu1-mesa-dev libhunspell-dev libjpeg-dev libmeshoptimizer-dev libminizip-dev libnanosvg-dev libnghttp2-dev libopenjp2-7-dev libpipewire-0.3-dev libpng-dev libsdl2-dev libvlc-dev libvlccore-dev libvorbis-dev libxft-dev libxml2-dev libxxhash-dev +$ sudo apt install cmake patchelf pkg-config libxml2-utils libalut-dev libaprutil1-dev libboost-fiber-dev libboost-json-dev libboost-program-options-dev libboost-regex-dev libboost-url-dev libexpat1-dev libfltk1.4-dev libfontconfig-dev libfreetype-dev libglu1-mesa-dev libhunspell-dev libjpeg-dev libmeshoptimizer-dev libminizip-dev libnanosvg-dev libnghttp2-dev libopenjp2-7-dev libpipewire-0.3-dev libpng-dev libsdl2-dev libvlc-dev libvlccore-dev libvorbis-dev libxft-dev libxml2-dev libxxhash-dev $ export LL_BUILD="-O3 -std=c++20 -fPIC -DLL_LINUX=1" $ cmake -DCMAKE_BUILD_TYPE:STRING=Release -DADDRESS_SIZE:STRING=64 -DUSE_OPENAL:BOOL=ON -DUSE_FMODSTUDIO:BOOL=OFF -DENABLE_MEDIA_PLUGINS:BOOL=ON -DLL_TESTS:BOOL=OFF -DNDOF:BOOL=ON -DROOT_PROJECT_NAME:STRING=Megapahit -DVIEWER_CHANNEL:STRING=Megapahit -DVIEWER_BINARY_NAME:STRING=megapahit -DBUILD_SHARED_LIBS:BOOL=OFF -DINSTALL:BOOL=ON -DPACKAGE:BOOL=ON ../indra $ make -j`nproc` @@ -43,7 +43,7 @@ $ megapahit ### Debian arm64 ``` -$ sudo apt install cmake pkg-config libxml2-utils libalut-dev libaprutil1-dev libboost-fiber-dev libboost-json-dev libboost-program-options-dev libboost-regex-dev libboost-url-dev libexpat1-dev libfltk1.4-dev libfontconfig-dev libfreetype-dev libglu1-mesa-dev libhunspell-dev libjpeg-dev libmeshoptimizer-dev libminizip-dev libnanosvg-dev libnghttp2-dev libopenjp2-7-dev libpipewire-0.3-dev libpng-dev libsdl2-dev libvlc-dev libvlccore-dev libvorbis-dev libxft-dev libxml2-dev libxxhash-dev +$ sudo apt install cmake patchelf pkg-config libxml2-utils libalut-dev libaprutil1-dev libboost-fiber-dev libboost-json-dev libboost-program-options-dev libboost-regex-dev libboost-url-dev libexpat1-dev libfltk1.4-dev libfontconfig-dev libfreetype-dev libglu1-mesa-dev libhunspell-dev libjpeg-dev libmeshoptimizer-dev libminizip-dev libnanosvg-dev libnghttp2-dev libopenjp2-7-dev libpipewire-0.3-dev libpng-dev libsdl2-dev libvlc-dev libvlccore-dev libvorbis-dev libxft-dev libxml2-dev libxxhash-dev $ export LL_BUILD="-O3 -std=c++20 -fPIC -DLL_LINUX=1" $ cmake -DCMAKE_BUILD_TYPE:STRING=Release -DADDRESS_SIZE:STRING=64 -DUSE_OPENAL:BOOL=ON -DUSE_FMODSTUDIO:BOOL=OFF -DENABLE_MEDIA_PLUGINS:BOOL=ON -DLL_TESTS:BOOL=OFF -DNDOF:BOOL=ON -DROOT_PROJECT_NAME:STRING=Megapahit -DVIEWER_CHANNEL:STRING=Megapahit -DVIEWER_BINARY_NAME:STRING=megapahit -DBUILD_SHARED_LIBS:BOOL=OFF -DINSTALL:BOOL=ON -DPACKAGE:BOOL=ON -DOPENGL_glu_LIBRARY:FILEPATH=/usr/lib/aarch64-linux-gnu/libGLU.so -DOPENGL_glx_LIBRARY:FILEPATH=/usr/lib/aarch64-linux-gnu/libGLX.so -DOPENGL_opengl_LIBRARY:FILEPATH=/usr/lib/aarch64-linux-gnu/libOpenGL.so ../indra $ make -j`nproc` @@ -55,7 +55,7 @@ $ megapahit ### Fedora ``` -$ sudo dnf install cmake gcc-c++ patch patchelf rpm-build perl-FindBin freealut-devel apr-util-devel boost-devel boost-url expat-devel fltk-devel glm-devel mesa-libGLU-devel hunspell-devel minizip-ng-compat-devel libnghttp2-devel nanosvg-devel openjpeg-devel pipewire-devel pulseaudio-libs-devel sdl2-compat-devel v-hacd-devel vlc-devel libvorbis-devel libXcursor-devel libXfixes-devel libXinerama-devel xxhash-devel +$ sudo dnf install cmake gcc-c++ patch patchelf rpm-build perl-FindBin freealut-devel apr-util-devel boost-devel cef-devel expat-devel fltk-devel glm-devel mesa-libGLU-devel hunspell-devel minizip-ng-compat-devel libnghttp2-devel nanosvg-devel openjpeg-devel pipewire-devel pulseaudio-libs-devel sdl2-compat-devel v-hacd-devel vlc-devel libvorbis-devel libXcursor-devel libXfixes-devel libXinerama-devel xxhash-devel $ export LL_BUILD="-O3 -std=c++20 -fPIC -DLL_LINUX=1" $ cmake -DCMAKE_BUILD_TYPE:STRING=Release -DADDRESS_SIZE:STRING=64 -DUSE_OPENAL:BOOL=ON -DUSE_FMODSTUDIO:BOOL=OFF -DENABLE_MEDIA_PLUGINS:BOOL=ON -DLL_TESTS:BOOL=OFF -DNDOF:BOOL=ON -DROOT_PROJECT_NAME:STRING=Megapahit -DVIEWER_CHANNEL:STRING=Megapahit -DVIEWER_BINARY_NAME:STRING=megapahit -DBUILD_SHARED_LIBS:BOOL=OFF -DINSTALL:BOOL=ON -DPACKAGE:BOOL=ON ../indra $ make -j`nproc` @@ -110,7 +110,7 @@ $ open newview/Megapahit.app ### openSUSE Tumbleweed ``` -$ sudo zypper install cmake gcc-c++ patch patchelf apr-util-devel boost-devel libboost_program_options-devel libboost_url1_91_0 libboost_url1_91_0-devel libboost_context-devel libboost_fiber-devel libboost_filesystem-devel libboost_regex-devel libboost_thread-devel libpng16-devel libxml++-devel libexpat-devel fltk-devel glm glu-devel hunspell-devel minizip-devel nanosvg-devel libnghttp2-devel openjpeg2-devel pipewire-devel libpulse-devel libSDL2_gfx-1_0-0 libSDL2_gfx-devel sdl2-compat-devel vlc-devel libvorbis-devel xxhash-devel zlib-ng-devel libXrender-devel libXcursor-devel libXfixes-devel libXext-devel libXft-devel libXinerama-devel freetype2-devel fontconfig-devel libjpeg8-devel libjpeg8-devel freealut-devel rpm-build +$ sudo zypper install cmake gcc-c++ patch patchelf apr-util-devel boost-devel libboost_program_options-devel libboost_url1_91_0 libboost_url1_91_0-devel libboost_context-devel libboost_fiber-devel libboost_filesystem-devel libboost_regex-devel libboost_thread-devel libpng16-devel libxml++-devel libexpat-devel fltk-devel glm-devel glu-devel hunspell-devel minizip-devel nanosvg-devel libnghttp2-devel openjpeg2-devel pipewire-devel libpulse-devel libSDL2_gfx-1_0-0 libSDL2_gfx-devel sdl2-compat-devel vlc-devel libvorbis-devel xxhash-devel zlib-ng-devel libXrender-devel libXcursor-devel libXfixes-devel libXext-devel libXft-devel libXinerama-devel freetype2-devel fontconfig-devel libjpeg8-devel libjpeg8-devel freealut-devel rpm-build $ export LL_BUILD="-O3 -std=c++20 -fPIC -DLL_LINUX=1" @@ -126,7 +126,7 @@ $ megapahit ### Ubuntu ``` -$ sudo apt install cmake pkg-config libxml2-utils libalut-dev libaprutil1-dev libboost-fiber-dev libboost-json-dev libboost-program-options-dev libboost-regex-dev libboost-url-dev libexpat1-dev libfltk1.4-dev libfontconfig-dev libfreetype-dev libglm-dev libglu1-mesa-dev libhunspell-dev libjpeg-dev libmeshoptimizer-dev libminizip-dev libnanosvg-dev libnghttp2-dev libopenjp2-7-dev libpipewire-0.3-dev libpng-dev libsdl2-dev libvlc-dev libvlccore-dev libvorbis-dev libxft-dev libxml2-dev libxxhash-dev +$ sudo apt install cmake patchelf pkg-config libxml2-utils libalut-dev libaprutil1-dev libboost-fiber-dev libboost-json-dev libboost-program-options-dev libboost-regex-dev libboost-url-dev libexpat1-dev libfltk1.4-dev libfontconfig-dev libfreetype-dev libglm-dev libglu1-mesa-dev libhunspell-dev libjpeg-dev libmeshoptimizer-dev libminizip-dev libnanosvg-dev libnghttp2-dev libopenjp2-7-dev libpipewire-0.3-dev libpng-dev libsdl2-dev libvlc-dev libvlccore-dev libvorbis-dev libxft-dev libxml2-dev libxxhash-dev $ export LL_BUILD="-O3 -std=c++20 -fPIC -DLL_LINUX=1" $ cmake -DCMAKE_BUILD_TYPE:STRING=Release -DADDRESS_SIZE:STRING=64 -DUSE_OPENAL:BOOL=ON -DUSE_FMODSTUDIO:BOOL=OFF -DENABLE_MEDIA_PLUGINS:BOOL=ON -DLL_TESTS:BOOL=OFF -DNDOF:BOOL=ON -DROOT_PROJECT_NAME:STRING=Megapahit -DVIEWER_CHANNEL:STRING=Megapahit -DVIEWER_BINARY_NAME:STRING=megapahit -DBUILD_SHARED_LIBS:BOOL=OFF -DINSTALL:BOOL=ON -DPACKAGE:BOOL=ON ../indra $ make -j`nproc` diff --git a/autobuild.xml b/autobuild.xml index 357ec9f952..571da61367 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -500,7 +500,7 @@ <key>hash_algorithm</key> <string>sha1</string> <key>url</key> - <string>https://github.com/secondlife/dullahan/releases/download/v1.14.0-r3/dullahan-1.14.0.202408091637_118.4.1_g3dd6078_chromium-118.0.5993.54-linux64-10322607516.tar.zst</string> + <string>https://github.com/secondlife/dullahan/releases/download/v1.25.0-CEF_139.0.40/dullahan-1.25.0.202510152245_139.0.40_g465474a_chromium-139.0.7258.139-linux64-18544680875.tar.zst</string> </map> <key>name</key> <string>linux64</string> diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 42e211c84d..90ca9866bb 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -16,6 +16,7 @@ include_guard() include(Variables) include(Linker) +include(UnixInstall) # We go to some trouble to set LL_BUILD to the set of relevant compiler flags. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{LL_BUILD}") @@ -127,7 +128,7 @@ endif (NOT CMAKE_CXX_COMPILER_ID MATCHES GNU AND WINDOWS) if (LINUX OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE ) - set( CMAKE_INSTALL_RPATH $ORIGIN $ORIGIN/../lib ) + set( CMAKE_INSTALL_RPATH ${INSTALL_LIBRARY_DIR} ) set(CMAKE_EXE_LINKER_FLAGS "-Wl,--exclude-libs,ALL") find_program(CCACHE_EXE ccache) @@ -190,6 +191,7 @@ if (LINUX OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set(CLANG_WARNINGS ${GCC_CLANG_COMPATIBLE_WARNINGS} # Put clang specific warning configuration here + -Wno-inconsistent-missing-override ) set(GCC_WARNINGS diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 25d673e49a..3f9134cb8f 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -12,10 +12,21 @@ if (DARWIN) elseif (WINDOWS) target_include_directories( ll::boost SYSTEM INTERFACE ${prefix_result}/../include) target_link_directories( ll::boost INTERFACE ${prefix_result}) - if ($ENV{MSYSTEM_CARCH} MATCHES aarch64) - set(sfx -vc143-mt-a64-1_91) + # Detect the actual toolset/version suffix from whatever vcpkg installed. + # Glob for boost_context-*.lib and strip the known prefix to get the suffix. + file(GLOB _boost_context_libs "${prefix_result}/boost_context-*.lib") + if (_boost_context_libs) + list(GET _boost_context_libs 0 _boost_context_lib) + get_filename_component(_boost_context_name "${_boost_context_lib}" NAME_WE) + string(REPLACE "boost_context" "" sfx "${_boost_context_name}") else () - set(sfx -vc143-mt-x64-1_91) + if ($ENV{MSYSTEM_CARCH} MATCHES aarch64) + set(sfx -vc143-mt-a64-1_91) + else () + set(sfx -vc143-mt-x64-1_91) + endif () + message(WARNING "Could not detect Boost suffix via glob; using fallback '${sfx}'. " + "Check that vcpkg installed boost into ${prefix_result}.") endif () else () find_package( Boost ) @@ -152,4 +163,3 @@ target_link_libraries(ll::boost INTERFACE if (LINUX) target_link_libraries(ll::boost INTERFACE rt) endif (LINUX) - diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index 31ed86213a..117c83353e 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -1,54 +1,187 @@ # -*- cmake -*- include(Linking) include(Prebuilt) +include(UnixInstall) include_guard() add_library( ll::cef INTERFACE IMPORTED ) -if (CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) +if (${LINUX_DISTRO} MATCHES arch) if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/dullahan_installed OR NOT ${dullahan_installed} EQUAL 0) - if (NOT EXISTS ${CMAKE_BINARY_DIR}/v1.14.0-r3.tar.gz) + file( + COPY /usr/src/cef/libcef_dll + DESTINATION ${CMAKE_BINARY_DIR} + ) + execute_process( + COMMAND sed -i "s/macro(L/cmake_minimum_required(VERSION 3.28)\\nmacro(SET_LIBRARY_TARGET_PROPERTIES)\\nendmacro()\\nmacro(L/" CMakeLists.txt + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/libcef_dll + ) + try_compile(LIBCEF_DLL_RESULT + PROJECT libcef_dll + SOURCE_DIR ${CMAKE_BINARY_DIR}/libcef_dll + BINARY_DIR ${CMAKE_BINARY_DIR}/libcef_dll + CMAKE_FLAGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + "-DCMAKE_CXX_FLAGS:STRING=-I/usr/include/cef -I/usr/src/cef -fPIC" + ) + if (${LIBCEF_DLL_RESULT}) + file( + COPY ${CMAKE_BINARY_DIR}/libcef_dll/libcef_dll_wrapper.a + DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE} + ) + endif () + if (NOT EXISTS ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10.tar.gz) file(DOWNLOAD - https://github.com/secondlife/dullahan/archive/refs/tags/v1.14.0-r3.tar.gz - ${CMAKE_BINARY_DIR}/v1.14.0-r3.tar.gz + https://github.com/secondlife/dullahan/archive/refs/tags/v1.30.0-CEF_147.0.10.tar.gz + ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10.tar.gz + ) + endif () + file(ARCHIVE_EXTRACT + INPUT ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10.tar.gz + DESTINATION ${CMAKE_BINARY_DIR} + ) + try_compile(DULLAHAN_RESULT + PROJECT dullahan + SOURCE_DIR ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10 + BINARY_DIR ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10 + CMAKE_FLAGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX:PATH=${LIBS_PREBUILT_DIR} + -DCMAKE_INSTALL_LIBDIR:PATH=${ARCH_PREBUILT_DIRS_RELEASE} + -DCEF_WRAPPER_DIR:PATH=/usr/include/cef + -DCEF_WRAPPER_BUILD_DIR:PATH=${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10 + -DCEF_LIBRARY_RELEASE:FILEPATH=${INSTALL_PREFIX}/${_LIB}/cef/libcef.so + -DCEF_DLL_LIBRARY_RELEASE:FILEPATH=${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a + "-DCMAKE_CXX_FLAGS:STRING=-I/usr/include/cef -I/usr/src/cef -DWRAPPING_CEF_SHARED" + ) + if (${DULLAHAN_RESULT}) + file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/bin/release) + file( + COPY ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10/dullahan_host + DESTINATION ${LIBS_PREBUILT_DIR}/bin/release + ) + file( + COPY ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10/libdullahan.a + DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE} + ) + file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/include/cef) + file( + COPY + ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10/src/dullahan.h + ${CMAKE_BINARY_DIR}/dullahan-1.30.0-CEF_147.0.10/src/dullahan_version.h + DESTINATION ${LIBS_PREBUILT_DIR}/include/cef + ) + file(WRITE ${PREBUILD_TRACKING_DIR}/dullahan_installed "0") + endif () + endif () +elseif (${LINUX_DISTRO} MATCHES fedora) + if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/dullahan_installed OR NOT ${dullahan_installed} EQUAL 0) + file( + COPY /usr/src/cef-146.0.11/libcef_dll + DESTINATION ${CMAKE_BINARY_DIR} + ) + execute_process( + COMMAND sed -i "s/macro(L/cmake_minimum_required(VERSION 3.28)\\nmacro(SET_LIBRARY_TARGET_PROPERTIES)\\nendmacro()\\nmacro(L/" CMakeLists.txt + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/libcef_dll + ) + try_compile(LIBCEF_DLL_RESULT + PROJECT libcef_dll + SOURCE_DIR ${CMAKE_BINARY_DIR}/libcef_dll + BINARY_DIR ${CMAKE_BINARY_DIR}/libcef_dll + CMAKE_FLAGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + "-DCMAKE_CXX_FLAGS:STRING=-I/usr/include/cef -I/usr/src/cef-146.0.11 -fPIC" + ) + if (${LIBCEF_DLL_RESULT}) + file( + COPY ${CMAKE_BINARY_DIR}/libcef_dll/libcef_dll_wrapper.a + DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE} + ) + endif () + if (NOT EXISTS ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12.tar.gz) + file(DOWNLOAD + https://github.com/secondlife/dullahan/archive/refs/tags/v1.29.0-CEF_146.0.12.tar.gz + ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12.tar.gz + ) + endif () + file(ARCHIVE_EXTRACT + INPUT ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12.tar.gz + DESTINATION ${CMAKE_BINARY_DIR} + ) + try_compile(DULLAHAN_RESULT + PROJECT dullahan + SOURCE_DIR ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12 + BINARY_DIR ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12 + CMAKE_FLAGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_PREFIX:PATH=${LIBS_PREBUILT_DIR} + -DCMAKE_INSTALL_LIBDIR:PATH=${ARCH_PREBUILT_DIRS_RELEASE} + -DCEF_WRAPPER_DIR:PATH=/usr/include/cef + -DCEF_WRAPPER_BUILD_DIR:PATH=${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12 + -DCEF_LIBRARY_RELEASE:FILEPATH=${INSTALL_PREFIX}/${_LIB}/cef/libcef.so + -DCEF_DLL_LIBRARY_RELEASE:FILEPATH=${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a + "-DCMAKE_CXX_FLAGS:STRING=-I/usr/include/cef -I/usr/src/cef-146.0.11 -DWRAPPING_CEF_SHARED" + ) + if (${DULLAHAN_RESULT}) + file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/bin/release) + file( + COPY ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12/dullahan_host + DESTINATION ${LIBS_PREBUILT_DIR}/bin/release + ) + file( + COPY ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12/libdullahan.a + DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE} + ) + file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/include/cef) + file( + COPY + ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12/src/dullahan.h + ${CMAKE_BINARY_DIR}/dullahan-1.29.0-CEF_146.0.12/src/dullahan_version.h + DESTINATION ${LIBS_PREBUILT_DIR}/include/cef + ) + file(WRITE ${PREBUILD_TRACKING_DIR}/dullahan_installed "0") + endif () + endif () +elseif (CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) + if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/dullahan_installed OR NOT ${dullahan_installed} EQUAL 0) + if (NOT EXISTS ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40.tar.gz) + file(DOWNLOAD + https://github.com/secondlife/dullahan/archive/refs/tags/v1.24.0-CEF_139.0.40.tar.gz + ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40.tar.gz ) endif () file(ARCHIVE_EXTRACT - INPUT ${CMAKE_BINARY_DIR}/v1.14.0-r3.tar.gz + INPUT ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40.tar.gz DESTINATION ${CMAKE_BINARY_DIR} ) execute_process( COMMAND sed -i "/#include <vector>/a #include <cstdint>" dullahan.h - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/dullahan-1.14.0-r3/src + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40/src ) file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/include/cef) try_compile(DULLAHAN_RESULT PROJECT dullahan - SOURCE_DIR ${CMAKE_BINARY_DIR}/dullahan-1.14.0-r3 - BINARY_DIR ${CMAKE_BINARY_DIR}/dullahan-1.14.0-r3 + SOURCE_DIR ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40 + BINARY_DIR ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40 CMAKE_FLAGS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} - -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_INSTALL_PREFIX:PATH=${LIBS_PREBUILT_DIR} -DCMAKE_INSTALL_LIBDIR:PATH=${ARCH_PREBUILT_DIRS_RELEASE} -DCMAKE_BUILD_WITH_INSTALL_RPATH:BOOL=ON - -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} -DUSE_SPOTIFY_CEF:BOOL=ON - -DSPOTIFY_CEF_URL:STRING=https://cef-builds.spotifycdn.com/cef_binary_118.4.1%2Bg3dd6078%2Bchromium-118.0.5993.54_linuxarm64_beta_minimal.tar.bz2 + -DSPOTIFY_CEF_URL:STRING=https://cef-builds.spotifycdn.com/cef_binary_139.0.40%2Bg465474a%2Bchromium-139.0.7258.139_linuxarm64_minimal.tar.bz2 -DPROJECT_ARCH:STRING=${CMAKE_SYSTEM_PROCESSOR} - -DENABLE_CXX11_ABI:BOOL=ON ) if (${DULLAHAN_RESULT}) execute_process( COMMAND ${CMAKE_MAKE_PROGRAM} install - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/dullahan-1.14.0-r3 + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40 OUTPUT_VARIABLE dullahan_installed ) file( COPY - ${CMAKE_BINARY_DIR}/dullahan-1.14.0-r3/src/dullahan.h - ${CMAKE_BINARY_DIR}/dullahan-1.14.0-r3/src/dullahan_version.h + ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40/src/dullahan.h + ${CMAKE_BINARY_DIR}/dullahan-1.24.0-CEF_139.0.40/src/dullahan_version.h DESTINATION ${LIBS_PREBUILT_DIR}/include/cef ) file(WRITE ${PREBUILD_TRACKING_DIR}/dullahan_installed "${dullahan_installed}") @@ -59,9 +192,17 @@ use_prebuilt_binary(dullahan) endif () execute_process( - COMMAND patchelf --remove-rpath bin/release/dullahan_host + COMMAND patchelf --set-rpath ${INSTALL_LIBRARY_DIR} bin/release/dullahan_host WORKING_DIRECTORY ${LIBS_PREBUILT_DIR} +) + +if (${LINUX_DISTRO} MATCHES arch OR (${LINUX_DISTRO} MATCHES fedora)) + target_include_directories( ll::cef SYSTEM INTERFACE /usr/include/cef/include) + execute_process( + COMMAND patchelf --add-rpath ${INSTALL_PREFIX}/${_LIB}/cef bin/release/dullahan_host + WORKING_DIRECTORY ${LIBS_PREBUILT_DIR} ) +endif () target_include_directories( ll::cef SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/cef) @@ -129,6 +270,9 @@ elseif (DARWIN) ) elseif (LINUX) + if (${LINUX_DISTRO} MATCHES arch OR (${LINUX_DISTRO} MATCHES fedora)) + target_link_directories( ll::cef INTERFACE ${INSTALL_PREFIX}/${_LIB}/cef ) + endif () target_link_libraries( ll::cef INTERFACE libdullahan.a cef diff --git a/indra/cmake/Discord.cmake b/indra/cmake/Discord.cmake index f474457b03..68e6f59ecb 100644 --- a/indra/cmake/Discord.cmake +++ b/indra/cmake/Discord.cmake @@ -9,7 +9,7 @@ target_compile_definitions(ll::discord_sdk INTERFACE LL_DISCORD=1) if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/discord_sdk_installed OR NOT ${discord_sdk_installed} EQUAL 0) file(ARCHIVE_EXTRACT - INPUT $ENV{HOME}/Downloads/DiscordSocialSdk-1.8.13395.zip + INPUT $ENV{HOME}/Downloads/DiscordSocialSdk-1.9.15780.zip DESTINATION ${CMAKE_BINARY_DIR} ) file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/include/discord_sdk) @@ -19,9 +19,12 @@ if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKIN ${CMAKE_BINARY_DIR}/discord_social_sdk/include/discordpp.h DESTINATION ${LIBS_PREBUILT_DIR}/include/discord_sdk ) + if ($ENV{MSYSTEM_CARCH} MATCHES aarch64) + set(DISCORD_PLATFORM /arm64) + endif () if (WINDOWS) file( - COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/bin/release/discord_partner_sdk.dll + COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/bin/release${DISCORD_PLATFORM}/discord_partner_sdk.dll DESTINATION ${LIBS_PREBUILT_DIR}/bin/release ) set(LIBRARY_EXTENSION lib) @@ -39,7 +42,7 @@ if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKIN ) else () file( - COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/lib/release/${LIBRARY_PREFIX}discord_partner_sdk.${LIBRARY_EXTENSION} + COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/lib/release${DISCORD_PLATFORM}/${LIBRARY_PREFIX}discord_partner_sdk.${LIBRARY_EXTENSION} DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE} ) endif () diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake index df8d96109f..4708834653 100644 --- a/indra/cmake/LLPrimitive.cmake +++ b/indra/cmake/LLPrimitive.cmake @@ -69,10 +69,19 @@ if (TRUE) elseif (WINDOWS) set(BOOST_CFLAGS -I${prefix_result}/../include) set(BOOST_LIBS -L${prefix_result}) - if ($ENV{MSYSTEM_CARCH} MATCHES aarch64) - set(BOOST_LIBRARY_SUFFIX -vc143-mt-a64-1_91) + # Detect actual toolset/version suffix from vcpkg-installed libs. + file(GLOB _boost_context_libs "${prefix_result}/boost_context-*.lib") + if (_boost_context_libs) + list(GET _boost_context_libs 0 _boost_context_lib) + get_filename_component(_boost_context_name "${_boost_context_lib}" NAME_WE) + string(REPLACE "boost_context" "" BOOST_LIBRARY_SUFFIX "${_boost_context_name}") else () - set(BOOST_LIBRARY_SUFFIX -vc143-mt-x64-1_91) + if ($ENV{MSYSTEM_CARCH} MATCHES aarch64) + set(BOOST_LIBRARY_SUFFIX -vc143-mt-a64-1_91) + else () + set(BOOST_LIBRARY_SUFFIX -vc143-mt-x64-1_91) + endif () + message(WARNING "Could not detect Boost suffix via glob in LLPrimitive; using fallback.") endif () elseif (CMAKE_SYSTEM_NAME MATCHES FreeBSD) set(BOOST_CFLAGS -I/usr/local/include) diff --git a/indra/cmake/UnixInstall.cmake b/indra/cmake/UnixInstall.cmake index 1fd17a0142..b82cbbcc2f 100644 --- a/indra/cmake/UnixInstall.cmake +++ b/indra/cmake/UnixInstall.cmake @@ -22,8 +22,8 @@ if (INSTALL) set(_LIB lib) endif () - set(INSTALL_LIBRARY_DIR ${INSTALL_PREFIX}/${_LIB} CACHE PATH - "Installation directory for read-only shared files.") + set(INSTALL_LIBRARY_DIR ${INSTALL_PREFIX}/${_LIB}/${VIEWER_BINARY_NAME} CACHE PATH + "Installation directory for dynamic library files and their resources.") set(INSTALL_SHARE_DIR ${INSTALL_PREFIX}/share CACHE PATH "Installation directory for read-only shared files.") diff --git a/indra/llwebrtc/CMakeLists.txt b/indra/llwebrtc/CMakeLists.txt index a01d9fc632..1c53b0263c 100644 --- a/indra/llwebrtc/CMakeLists.txt +++ b/indra/llwebrtc/CMakeLists.txt @@ -77,11 +77,11 @@ if (INSTALL) if (DARWIN) set(_LIB ../Frameworks) elseif (${LINUX_DISTRO} MATCHES debian OR (${LINUX_DISTRO} MATCHES ubuntu)) - set(_LIB lib/${ARCH}-linux-gnu) + set(_LIB lib/${ARCH}-linux-gnu/${VIEWER_BINARY_NAME}) elseif (${LINUX_DISTRO} MATCHES fedora OR (${LINUX_DISTRO} MATCHES opensuse-tumbleweed) OR (${LINUX_DISTRO} MATCHES gentoo)) - set(_LIB lib${ADDRESS_SIZE}) + set(_LIB lib${ADDRESS_SIZE}/${VIEWER_BINARY_NAME}) else () - set(_LIB lib) + set(_LIB lib/${VIEWER_BINARY_NAME}) endif () if (WINDOWS) diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 236e117aa7..4736eef420 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -50,7 +50,10 @@ if (LINUX) ) list(APPEND media_plugin_cef_SOURCE_FILES ${LINUX_VOLUME_CATCHER}) - set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id -Wl,-rpath,'$ORIGIN:$ORIGIN/../../lib'") + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--build-id") + if (${LINUX_DISTRO} MATCHES arch OR (${LINUX_DISTRO} MATCHES fedora)) + set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH};${INSTALL_PREFIX}/${_LIB}/cef) + endif () list(APPEND media_plugin_cef_LINK_LIBRARIES llwindow ) elseif (DARWIN) list(APPEND media_plugin_cef_SOURCE_FILES volume_catcher_null.cpp) @@ -145,45 +148,62 @@ if (INSTALL) ) elseif (LINUX) if (${LINUX_DISTRO} MATCHES debian OR (${LINUX_DISTRO} MATCHES ubuntu)) - set(_LIB lib/${ARCH}-linux-gnu) + set(_LIB lib/${ARCH}-linux-gnu/${VIEWER_BINARY_NAME}) elseif (${LINUX_DISTRO} MATCHES fedora OR (${LINUX_DISTRO} MATCHES opensuse-tumbleweed) OR (${LINUX_DISTRO} MATCHES gentoo)) - set(_LIB lib${ADDRESS_SIZE}) + set(_LIB lib${ADDRESS_SIZE}/${VIEWER_BINARY_NAME}) else () - set(_LIB lib) + set(_LIB lib/${VIEWER_BINARY_NAME}) endif () if (${LINUX_DISTRO} MATCHES arch) install( - PROGRAMS - ${AUTOBUILD_INSTALL_DIR}/bin/release/chrome-sandbox - ${AUTOBUILD_INSTALL_DIR}/bin/release/dullahan_host + PROGRAMS ${AUTOBUILD_INSTALL_DIR}/bin/release/dullahan_host DESTINATION lib/${VIEWER_BINARY_NAME} - #PERMISSIONS SETUID OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) - else (${LINUX_DISTRO} MATCHES arch) + elseif (${LINUX_DISTRO} MATCHES fedora) + install( + PROGRAMS ${AUTOBUILD_INSTALL_DIR}/bin/release/dullahan_host + DESTINATION libexec/${VIEWER_BINARY_NAME} + ) + else () install( PROGRAMS ${AUTOBUILD_INSTALL_DIR}/bin/release/chrome-sandbox ${AUTOBUILD_INSTALL_DIR}/bin/release/dullahan_host DESTINATION libexec/${VIEWER_BINARY_NAME} - #PERMISSIONS SETUID OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) - endif (${LINUX_DISTRO} MATCHES arch) - install( - FILES - ${ARCH_PREBUILT_DIRS_RELEASE}/libcef.so - ${ARCH_PREBUILT_DIRS_RELEASE}/libvk_swiftshader.so - ${AUTOBUILD_INSTALL_DIR}/bin/release/snapshot_blob.bin - ${AUTOBUILD_INSTALL_DIR}/bin/release/v8_context_snapshot.bin - ${AUTOBUILD_INSTALL_DIR}/resources/chrome_100_percent.pak - ${AUTOBUILD_INSTALL_DIR}/resources/chrome_200_percent.pak - ${AUTOBUILD_INSTALL_DIR}/resources/icudtl.dat - ${AUTOBUILD_INSTALL_DIR}/resources/resources.pak - DESTINATION ${_LIB} + endif () + if (NOT (${LINUX_DISTRO} MATCHES arch OR (${LINUX_DISTRO} MATCHES fedora))) + file(MAKE_DIRECTORY ${AUTOBUILD_INSTALL_DIR}/lib/release/${VIEWER_BINARY_NAME}) + file(CREATE_LINK + "../libGLESv2.so" + "${AUTOBUILD_INSTALL_DIR}/lib/release/${VIEWER_BINARY_NAME}/libGLESv2.so" + SYMBOLIC ) - install( - DIRECTORY ${AUTOBUILD_INSTALL_DIR}/resources/locales - DESTINATION ${_LIB} + file(CREATE_LINK + "../libvulkan.so.1" + "${AUTOBUILD_INSTALL_DIR}/lib/release/${VIEWER_BINARY_NAME}/libvulkan.so.1" + SYMBOLIC + ) + install( + FILES + ${ARCH_PREBUILT_DIRS_RELEASE}/libcef.so + ${ARCH_PREBUILT_DIRS_RELEASE}/libvk_swiftshader.so + ${ARCH_PREBUILT_DIRS_RELEASE}/libEGL.so + ${ARCH_PREBUILT_DIRS_RELEASE}/v8_context_snapshot.bin + ${ARCH_PREBUILT_DIRS_RELEASE}/vk_swiftshader_icd.json + ${ARCH_PREBUILT_DIRS_RELEASE}/${VIEWER_BINARY_NAME}/libGLESv2.so + ${ARCH_PREBUILT_DIRS_RELEASE}/${VIEWER_BINARY_NAME}/libvulkan.so.1 + ${AUTOBUILD_INSTALL_DIR}/resources/chrome_100_percent.pak + ${AUTOBUILD_INSTALL_DIR}/resources/chrome_200_percent.pak + ${AUTOBUILD_INSTALL_DIR}/resources/icudtl.dat + ${AUTOBUILD_INSTALL_DIR}/resources/resources.pak + DESTINATION ${_LIB} ) + install( + DIRECTORY ${AUTOBUILD_INSTALL_DIR}/resources/locales + DESTINATION ${_LIB} + ) + endif () elseif (WINDOWS) set(_LIB llplugin) install( @@ -213,7 +233,7 @@ if (INSTALL) DESTINATION llplugin ) else () - set(_LIB lib) + set(_LIB lib/${VIEWER_BINARY_NAME}) endif () if (NOT WINDOWS) install(TARGETS ${PROJECT_NAME} DESTINATION ${_LIB}) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index a2b664c755..d5ec3dbb20 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -957,7 +957,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { authResponse(message_in); } -#if !LL_LINUX if (message_name == "edit_undo") { mCEFLib->editUndo(); @@ -966,7 +965,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mCEFLib->editRedo(); } -#endif if (message_name == "edit_cut") { mCEFLib->editCut(); @@ -979,7 +977,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mCEFLib->editPaste(); } -#if !LL_LINUX if (message_name == "edit_delete") { mCEFLib->editDelete(); @@ -992,7 +989,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mCEFLib->viewSource(); } -#endif } else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) { @@ -1176,28 +1172,19 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD // void MediaPluginCEF::checkEditState() { -#if !LL_LINUX bool can_undo = mCEFLib->editCanUndo(); bool can_redo = mCEFLib->editCanRedo(); -#endif bool can_cut = mCEFLib->editCanCut(); bool can_copy = mCEFLib->editCanCopy(); bool can_paste = mCEFLib->editCanPaste(); -#if !LL_LINUX bool can_delete = mCEFLib->editCanDelete(); bool can_select_all = mCEFLib->editCanSelectAll(); -#endif -#if LL_LINUX - if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) -#else if ((can_undo != mCanUndo) || (can_redo != mCanRedo) || (can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste) || (can_delete != mCanDelete) || (can_select_all != mCanSelectAll)) -#endif { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); -#if !LL_LINUX if (can_undo != mCanUndo) { mCanUndo = can_undo; @@ -1209,7 +1196,6 @@ void MediaPluginCEF::checkEditState() mCanRedo = can_redo; message.setValueBoolean("redo", can_redo); } -#endif if (can_cut != mCanCut) { @@ -1229,7 +1215,6 @@ void MediaPluginCEF::checkEditState() message.setValueBoolean("paste", can_paste); } -#if !LL_LINUX if (can_delete != mCanDelete) { mCanDelete = can_delete; @@ -1241,7 +1226,6 @@ void MediaPluginCEF::checkEditState() mCanSelectAll = can_select_all; message.setValueBoolean("select_all", can_select_all); } -#endif sendMessage(message); } diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt index b8b3bd68f3..96790a8037 100644 --- a/indra/media_plugins/libvlc/CMakeLists.txt +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -88,11 +88,11 @@ if (INSTALL) DESTINATION ${_LIB}/plugins ) elseif (${LINUX_DISTRO} MATCHES debian OR (${LINUX_DISTRO} MATCHES ubuntu)) - set(_LIB lib/${ARCH}-linux-gnu) + set(_LIB lib/${ARCH}-linux-gnu/${VIEWER_BINARY_NAME}) elseif (${LINUX_DISTRO} MATCHES fedora OR (${LINUX_DISTRO} MATCHES opensuse-tumbleweed) OR (${LINUX_DISTRO} MATCHES gentoo)) - set(_LIB lib${ADDRESS_SIZE}) + set(_LIB lib${ADDRESS_SIZE}/${VIEWER_BINARY_NAME}) else () - set(_LIB lib) + set(_LIB lib/${VIEWER_BINARY_NAME}) endif () if (WINDOWS) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${PROJECT_NAME}.dll DESTINATION llplugin) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7812735867..e070fb3da3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -50,9 +50,6 @@ include(VisualLeakDetector) #include(VulkanGltf) include(ZLIBNG) include(LLPrimitive) -if (CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) - include(UnixInstall) -endif () if (ENABLE_MEDIA_PLUGINS) include(LibVLCPlugin) @@ -1534,7 +1531,6 @@ if (NOT (DARWIN OR WINDOWS)) llappviewerlinux.cpp PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" - COMPILE_FLAGS "-DAPP_PLUGIN_DIR=\\\"${INSTALL_LIBRARY_DIR}\\\"" ) #LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp) if (NOT CMAKE_CXX_COMPILER_ID MATCHES AppleClang) @@ -2206,8 +2202,14 @@ endif () if (ENABLE_MEDIA_PLUGINS) target_link_libraries(${VIEWER_BINARY_NAME} ll::libvlc ) + # Tell the viewer source which media-library version headers are + # actually available in this build, so version reporting in + # llappviewer.cpp is gated on the build configuration rather than on + # a CPU/compiler macro. Mirrors the link availability above exactly. + target_compile_definitions(${VIEWER_BINARY_NAME} PRIVATE LL_VLC=1) if (DARWIN OR LINUX) target_link_libraries(${VIEWER_BINARY_NAME} ll::cef ) + target_compile_definitions(${VIEWER_BINARY_NAME} PRIVATE LL_CEF=1) endif () endif () @@ -2399,7 +2401,7 @@ if (LINUX) set(CPACK_RPM_PACKAGE_DESCRIPTION ${VIEWER_PACKAGE_DESCRIPTION} CACHE STRING "RPM package description.") if (${LINUX_DISTRO} MATCHES fedora) - set(CPACK_RPM_PACKAGE_REQUIRES "freealut, apr-util, boost-fiber, boost-program-options, boost-regex, boost-thread, boost-url, expat, fltk, mesa-libGLU, hunspell, libnghttp2, openjpeg, sdl2-compat, vlc-libs, vlc-plugins-base, libvorbis" + set(CPACK_RPM_PACKAGE_REQUIRES "freealut, apr-util, boost-fiber, boost-program-options, boost-regex, boost-thread, boost-url, cef, expat, fltk, mesa-libGLU, hunspell, minizip-ng-compat, libnghttp2, openjpeg, sdl2-compat, vlc-libs, vlc-plugins-base, libvorbis" CACHE STRING "RPM package requirements.") else () set(CPACK_RPM_PACKAGE_REQUIRES "libalut0, libapr-util1-0, libboost_fiber1_91_0, libboost_program_options1_91_0, libboost_regex1_91_0, libboost_thread1_91_0, libboost_url1_91_0, libboost_url1_91_0-x86-64-v3, libpng16-16 expat, libfltk1_3, libGLU1, libhunspell-1_7-0, libnghttp2-14, openjpeg2, libSDL2-2_0-0, libvlc5, libvorbis0" diff --git a/indra/newview/FixBundle.cmake.in b/indra/newview/FixBundle.cmake.in index 77b4683c88..d915cac35b 100644 --- a/indra/newview/FixBundle.cmake.in +++ b/indra/newview/FixBundle.cmake.in @@ -94,14 +94,17 @@ file(CREATE_LINK "${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/libicuuc.78.dylib" SYMBOLIC ) +if(@ENABLE_MEDIA_PLUGINS@) file(CREATE_LINK "../../../../Frameworks/Chromium Embedded Framework.framework" "${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework" SYMBOLIC ) +endif() fixup_bundle(${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/MacOS/${VIEWER_CHANNEL} "" "${dirs}") +if(@ENABLE_MEDIA_PLUGINS@) file(CHMOD "${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/DullahanHelper.app/Contents/MacOS/DullahanHelper" "${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/DullahanHelper (Alerts).app/Contents/MacOS/DullahanHelper (Alerts)" @@ -110,7 +113,9 @@ file(CHMOD "${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks/DullahanHelper (Renderer).app/Contents/MacOS/DullahanHelper (Renderer)" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) +endif() +if(@ENABLE_MEDIA_PLUGINS@) execute_process( COMMAND hdiutil detach /Volumes/VLC\ media\ player COMMAND lipo libalut.0.dylib @@ -158,9 +163,9 @@ execute_process( COMMAND lipo libbz2.1.0.8.dylib -thin ${CMAKE_OSX_ARCHITECTURES} -output libbz2.1.0.8.dylib - COMMAND lipo libexpat.1.11.3.dylib + COMMAND lipo libexpat.1.12.1.dylib -thin ${CMAKE_OSX_ARCHITECTURES} - -output libexpat.1.11.3.dylib + -output libexpat.1.12.1.dylib COMMAND lipo libfreetype.6.dylib -thin ${CMAKE_OSX_ARCHITECTURES} -output libfreetype.6.dylib @@ -233,6 +238,7 @@ execute_process( WORKING_DIRECTORY ${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Frameworks ERROR_QUIET ) +endif() message("By default, the situation is assumed to be the strictest, an Apple Silicon Mac with the default security settings. Running a native self-built viewer on it without correct codesigning would lead to a crash. Also, codesigning requires administrative access. If you believe you're not in such a situation, you can remove the sudos in this file.") execute_process( @@ -258,7 +264,7 @@ execute_process( Frameworks/libbrotlidec.1.2.0.dylib Frameworks/libbz2.1.0.8.dylib Frameworks/libdiscord_partner_sdk.dylib - Frameworks/libexpat.1.11.3.dylib + Frameworks/libexpat.1.12.1.dylib Frameworks/libfreetype.6.dylib Frameworks/libhunspell-1.7.0.dylib Frameworks/libiconv.2.dylib @@ -637,6 +643,7 @@ execute_process( Resources/SLPlugin.app/Contents/Frameworks/DullahanHelper\ \(Plugin\).app/Contents/MacOS/DullahanHelper\ \(Plugin\) WORKING_DIRECTORY ${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents ) +if(@ENABLE_MEDIA_PLUGINS@) execute_process( COMMAND sudo codesign -f -s ${SIGNING_IDENTITY} --timestamp -o runtime --runtime-version ${CMAKE_OSX_DEPLOYMENT_TARGET} DullahanHelper.app @@ -657,6 +664,7 @@ execute_process( DullahanHelper\ \(Renderer\).app WORKING_DIRECTORY ${viewer_BINARY_DIR}/${VIEWER_CHANNEL}.app/Contents/Resources/SLPlugin.app/Contents/Frameworks ) +endif() execute_process( COMMAND sudo codesign -f -s ${SIGNING_IDENTITY} --timestamp -o runtime --runtime-version ${CMAKE_OSX_DEPLOYMENT_TARGET} --entitlements ${CMAKE_SOURCE_DIR}/newview/slplugin.entitlements diff --git a/indra/newview/FixPackage.cmake.in b/indra/newview/FixPackage.cmake.in index e67026aabb..4ae777c2f4 100644 --- a/indra/newview/FixPackage.cmake.in +++ b/indra/newview/FixPackage.cmake.in @@ -158,9 +158,9 @@ execute_process( COMMAND lipo libbz2.1.0.8.dylib -thin ${CMAKE_OSX_ARCHITECTURES} -output libbz2.1.0.8.dylib - COMMAND lipo libexpat.1.11.3.dylib + COMMAND lipo libexpat.1.12.1.dylib -thin ${CMAKE_OSX_ARCHITECTURES} - -output libexpat.1.11.3.dylib + -output libexpat.1.12.1.dylib COMMAND lipo libfreetype.6.dylib -thin ${CMAKE_OSX_ARCHITECTURES} -output libfreetype.6.dylib @@ -258,7 +258,7 @@ execute_process( Frameworks/libbrotlidec.1.2.0.dylib Frameworks/libbz2.1.0.8.dylib Frameworks/libdiscord_partner_sdk.dylib - Frameworks/libexpat.1.11.3.dylib + Frameworks/libexpat.1.12.1.dylib Frameworks/libfreetype.6.dylib Frameworks/libhunspell-1.7.0.dylib Frameworks/libiconv.2.dylib diff --git a/indra/newview/PKGBUILD.in b/indra/newview/PKGBUILD.in index 3de9558000..b2830ed145 100644 --- a/indra/newview/PKGBUILD.in +++ b/indra/newview/PKGBUILD.in @@ -6,7 +6,7 @@ pkgdesc="${VIEWER_PACKAGE_COMMENT}" arch=('${CMAKE_SYSTEM_PROCESSOR}') url="https://${VIEWER_PACKAGE_DOMAIN_NAME}" license=('LGPL-2.1') -depends=(freealut apr-util at-spi2-core boost-libs fltk glu hunspell libnghttp2 openjpeg2 sdl2 vlc libvorbis) +depends=(freealut apr-util at-spi2-core boost-libs cef fltk glu hunspell libnghttp2 openjpeg2 sdl2 vlc libvorbis) package() { cd "$startdir" diff --git a/indra/newview/ViewerInstall.cmake b/indra/newview/ViewerInstall.cmake index 56a3394943..7717605f1f 100644 --- a/indra/newview/ViewerInstall.cmake +++ b/indra/newview/ViewerInstall.cmake @@ -130,18 +130,29 @@ elseif (WINDOWS) set(BOOST_PLATFORM x${ADDRESS_SIZE}) endif () + # Detect the actual Boost DLL suffix from vcpkg-installed binaries. + file(GLOB _boost_context_dlls "${prefix_result}/../bin/boost_context-*.dll") + if (_boost_context_dlls) + list(GET _boost_context_dlls 0 _boost_context_dll) + get_filename_component(_boost_context_dll_name "${_boost_context_dll}" NAME_WE) + string(REPLACE "boost_context" "" BOOST_DLL_SFX "${_boost_context_dll_name}") + else () + set(BOOST_DLL_SFX -vc143-mt-${BOOST_PLATFORM}-1_91) + message(WARNING "Could not detect Boost DLL suffix via glob; using fallback '${BOOST_DLL_SFX}'.") + endif () + install( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${VIEWER_BINARY_NAME}.exe ${prefix_result}/../bin/OpenAL32.dll ${prefix_result}/../bin/alut.dll - ${prefix_result}/../bin/boost_context-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_fiber-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_filesystem-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_json-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_program_options-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_thread-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_url-vc143-mt-${BOOST_PLATFORM}-1_91.dll + ${prefix_result}/../bin/boost_context${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_fiber${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_filesystem${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_json${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_program_options${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_thread${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_url${BOOST_DLL_SFX}.dll ${prefix_result}/../bin/brotlicommon.dll ${prefix_result}/../bin/brotlidec.dll ${prefix_result}/../bin/bz2.dll @@ -176,8 +187,8 @@ elseif (WINDOWS) install( PROGRAMS - ${prefix_result}/../bin/boost_context-vc143-mt-${BOOST_PLATFORM}-1_91.dll - ${prefix_result}/../bin/boost_fiber-vc143-mt-${BOOST_PLATFORM}-1_91.dll + ${prefix_result}/../bin/boost_context${BOOST_DLL_SFX}.dll + ${prefix_result}/../bin/boost_fiber${BOOST_DLL_SFX}.dll ${prefix_result}/../bin/libapr-1.dll ${prefix_result}/../bin/libaprutil-1.dll ${prefix_result}/../bin/libexpat.dll @@ -201,7 +212,7 @@ if (LINUX) if (USE_DISCORD) install( FILES ${ARCH_PREBUILT_DIRS_RELEASE}/libdiscord_partner_sdk.so - DESTINATION ${_LIB} + DESTINATION ${_LIB}/${VIEWER_BINARY_NAME} ) endif () if (USE_FMODSTUDIO) @@ -209,7 +220,7 @@ if (LINUX) ${ARCH_PREBUILT_DIRS_RELEASE}/libfmod.so ${ARCH_PREBUILT_DIRS_RELEASE}/libfmod.so.13 ${ARCH_PREBUILT_DIRS_RELEASE}/libfmod.so.13.34 - DESTINATION ${_LIB}) + DESTINATION ${_LIB}/${VIEWER_BINARY_NAME}) endif (USE_FMODSTUDIO) endif (LINUX) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 481cafafd1..8b6c5e2e1a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1365,6 +1365,63 @@ <integer>1</integer> </map> <!-- End NaCl/Firestorm port --> + <!-- OTS over-the-shoulder aim settings --> + <key>OTSEnabled</key> + <map> + <key>Comment</key> + <string>When true, M key enters OTS shoulder cam instead of first-person mouselook</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>OTSCameraDistance</key> + <map> + <key>Comment</key> + <string>OTS camera distance behind avatar (meters)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>3.0</real> + </map> + <key>OTSCameraSide</key> + <map> + <key>Comment</key> + <string>OTS camera side offset (negative = right of avatar)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>-0.5</real> + </map> + <key>OTSCameraHeight</key> + <map> + <key>Comment</key> + <string>OTS camera height above avatar root (meters)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.5</real> + </map> + <key>OTSFocusDistance</key> + <map> + <key>Comment</key> + <string>OTS focus point distance in front of avatar (meters)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>10.0</real> + </map> + <!-- End OTS settings --> <key>CameraOffset</key> <map> <key>Comment</key> @@ -1402,8 +1459,8 @@ <key>Value</key> <array> <real>-3.0</real> - <real>0.5</real> - <real>0.2</real> + <real>0.0</real> + <real>0.75</real> </array> </map> <key>CameraOffsetScale</key> @@ -3272,9 +3329,9 @@ <string>Vector3D</string> <key>Value</key> <array> - <real>0.9</real> - <real>0.5</real> - <real>0.2</real> + <real>1.0</real> + <real>0.0</real> + <real>1.0</real> </array> </map> <key>AvatarSitRotation</key> @@ -4684,6 +4741,28 @@ <key>Value</key> <integer>0</integer> </map> + <key>KeepCameraOnLocalTeleport</key> + <map> + <key>Comment</key> + <string>Do not reset the camera position or mode when teleporting within the same region.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>DisableTeleportScreens</key> + <map> + <key>Comment</key> + <string>Do not show the fullscreen teleport progress/black screen during teleports.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>MiniMapAutoCenter</key> <map> <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 23647487b0..75a9ef58fc 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2123,6 +2123,13 @@ std::ostream& operator<<(std::ostream &s, const LLAgent &agent) //----------------------------------------------------------------------------- bool LLAgent::needsRenderAvatar() { + // OTS mode: always render avatar — we are in third-person even though + // mouselook input is active. + if (gAgentCamera.cameraOTS()) + { + return mShowAvatar && mOutfitChosen; + } + if (gAgentCamera.cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson) { return false; @@ -2134,6 +2141,11 @@ bool LLAgent::needsRenderAvatar() // true if we need to render your own avatar's head. bool LLAgent::needsRenderHead() { + // OTS mode: always render head — avatar is fully visible. + if (gAgentCamera.cameraOTS()) + { + return mShowAvatar; + } return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !gAgentCamera.cameraMouselook()); } @@ -2247,7 +2259,8 @@ void LLAgent::endAnimationUpdateUI() } // clean up UI from mode we're leaving - if (gAgentCamera.getLastCameraMode() == CAMERA_MODE_MOUSELOOK ) + if (gAgentCamera.getLastCameraMode() == CAMERA_MODE_MOUSELOOK + || gAgentCamera.getLastCameraMode() == CAMERA_MODE_OTS) { gToolBarView->setToolBarsVisible(true); // show mouse cursor @@ -2369,7 +2382,8 @@ void LLAgent::endAnimationUpdateUI() //--------------------------------------------------------------------- // Set up UI for mode we're entering //--------------------------------------------------------------------- - if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) + if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK + || gAgentCamera.getCameraMode() == CAMERA_MODE_OTS) { // clean up UI // first show anything hidden by UI toggle diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 369a6d3697..6f9f8bfa2a 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1176,7 +1176,7 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y) LLVector3 headLookAxis; LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance()); - if (cameraMouselook()) + if (cameraMouselook() || cameraOTS()) { lookAtType = LOOKAT_TARGET_MOUSELOOK; } @@ -1409,7 +1409,7 @@ void LLAgentCamera::updateCamera() gAgent.setShowAvatar(true); } - if (isAgentAvatarValid() && (mCameraMode != CAMERA_MODE_MOUSELOOK)) + if (isAgentAvatarValid() && mCameraMode != CAMERA_MODE_MOUSELOOK) { gAgentAvatarp->updateAttachmentVisibility(mCameraMode); } @@ -1497,7 +1497,8 @@ void LLAgentCamera::updateCamera() } gAgent.setLastPositionGlobal(global_pos); - if (LLVOAvatar::sVisibleInFirstPerson && isAgentAvatarValid() && !gAgentAvatarp->isSitting() && cameraMouselook()) + // Exclude OTS — shoulder camera position must not be overridden by head-tracking. + if (LLVOAvatar::sVisibleInFirstPerson && isAgentAvatarValid() && !gAgentAvatarp->isSitting() && cameraMouselook() && !cameraOTS()) { LLVector3 head_pos = gAgentAvatarp->mHeadp->getWorldPosition() + LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() + @@ -1598,6 +1599,19 @@ LLVector3d LLAgentCamera::calcFocusPositionTargetGlobal() mFocusTargetGlobal = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedFocus()); return mFocusTargetGlobal; } + else if (mCameraMode == CAMERA_MODE_OTS) + { + // Focus in front of avatar at aim height + static LLCachedControl<F32> ots_focus_dist(gSavedSettings, "OTSFocusDistance", 10.0f); + static LLCachedControl<F32> ots_height(gSavedSettings, "OTSCameraHeight", 0.5f); + static LLCachedControl<F32> ots_side(gSavedSettings, "OTSCameraSide", -0.5f); + LLVector3 focus_local((F32)ots_focus_dist, (F32)ots_side * 0.3f, (F32)ots_height * 0.5f); + LLQuaternion agent_rot = gAgent.getFrameAgent().getQuaternion(); + LLVector3 focus_world = focus_local * agent_rot; + LLVector3d avatar_pos = gAgent.getPosGlobalFromAgent(getAvatarRootPosition()); + mFocusTargetGlobal = avatar_pos + LLVector3d(focus_world); + return mFocusTargetGlobal; + } else if (mCameraMode == CAMERA_MODE_MOUSELOOK) { LLVector3d at_axis(1.0, 0.0, 0.0); @@ -1776,6 +1790,18 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(bool *hit_limit) { camera_position_global = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedPosition()); } + else if (mCameraMode == CAMERA_MODE_OTS) + { + // Shoulder offset camera — avatar-local space: X=forward, Y=left, Z=up + static LLCachedControl<F32> ots_dist(gSavedSettings, "OTSCameraDistance", 3.0f); + static LLCachedControl<F32> ots_side(gSavedSettings, "OTSCameraSide", -0.5f); + static LLCachedControl<F32> ots_height(gSavedSettings, "OTSCameraHeight", 0.5f); + LLVector3 local_offset(-(F32)ots_dist, (F32)ots_side, (F32)ots_height); + LLQuaternion agent_rot = gAgent.getFrameAgent().getQuaternion(); + LLVector3 world_offset = local_offset * agent_rot; + LLVector3d avatar_pos = gAgent.getPosGlobalFromAgent(getAvatarRootPosition()); + camera_position_global = avatar_pos + LLVector3d(world_offset); + } else if (mCameraMode == CAMERA_MODE_MOUSELOOK) { if (!isAgentAvatarValid() || gAgentAvatarp->mDrawable.isNull()) @@ -2244,6 +2270,58 @@ void LLAgentCamera::changeCameraToDefault() //----------------------------------------------------------------------------- +// changeCameraToOTS() +// Over-the-shoulder aim mode. +// Calls changeCameraToMouselook() to inherit ALL of its input setup +// (cursor hiding, mouse capture, control flags, focus management), +// then immediately overrides mCameraMode to CAMERA_MODE_OTS so that +// calcCameraPositionTargetGlobal places the camera at the shoulder offset +// instead of the avatar's eye position. +// Avatar rendering is handled explicitly in needsRenderAvatar() and needsRenderHead(). +//----------------------------------------------------------------------------- +void LLAgentCamera::changeCameraToOTS() +{ + if (mCameraMode != CAMERA_MODE_OTS) + { + // Inherit everything from mouselook: cursor lock, mouse capture, + // AGENT_CONTROL_MOUSELOOK flag, keyboard focus clear, etc. + changeCameraToMouselook(false); + + // Override mCameraMode to OTS so position/focus calculations + // use the shoulder offset instead of the eye position. + mCameraMode = CAMERA_MODE_OTS; + + // changeCameraToMouselook hid attachments via updateAttachmentVisibility + // with CAMERA_MODE_MOUSELOOK. Restore full visibility for OTS mode. + if (isAgentAvatarValid()) + { + gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); + } + + // Start the camera animation LAST, after mCameraMode is OTS and after + // changeCameraToMouselook(false) has cleared mCameraAnimating via its + // animate=false branch. The rendered camera is still at the old + // (third-person) position this frame, so startCameraAnimation snapshots + // that as the start point and updateCamera lerps to the OTS shoulder + // target over ZoomTime seconds — matching the mouselook transition feel. + startCameraAnimation(); + } +} + +//----------------------------------------------------------------------------- +// changeCameraFromOTS() +//----------------------------------------------------------------------------- +void LLAgentCamera::changeCameraFromOTS() +{ + if (mCameraMode == CAMERA_MODE_OTS) + { + // changeCameraToDefault handles clearing AGENT_CONTROL_MOUSELOOK, + // showing the cursor, and restoring the normal camera mode. + changeCameraToDefault(); + } +} + +//----------------------------------------------------------------------------- // changeCameraToFollow() //----------------------------------------------------------------------------- void LLAgentCamera::changeCameraToFollow(bool animate) @@ -2336,7 +2414,7 @@ void LLAgentCamera::changeCameraToThirdPerson(bool animate) } mCameraLag.clearVec(); - if (mCameraMode == CAMERA_MODE_MOUSELOOK) + if (mCameraMode == CAMERA_MODE_MOUSELOOK || mCameraMode == CAMERA_MODE_OTS) { mCurrentCameraDistance = MIN_CAMERA_DISTANCE; mTargetCameraDistance = MIN_CAMERA_DISTANCE; diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index d277fd6158..ac1a36a6c2 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -43,7 +43,8 @@ enum ECameraMode CAMERA_MODE_THIRD_PERSON, CAMERA_MODE_MOUSELOOK, CAMERA_MODE_CUSTOMIZE_AVATAR, - CAMERA_MODE_FOLLOW + CAMERA_MODE_FOLLOW, + CAMERA_MODE_OTS // Over-the-shoulder: mouselook input + third-person camera }; /** Camera Presets for CAMERA_MODE_THIRD_PERSON */ @@ -93,10 +94,14 @@ public: void changeCameraToThirdPerson(bool animate = true); void changeCameraToCustomizeAvatar(); // Trigger transition animation void changeCameraToFollow(bool animate = true); // Ventrella + void changeCameraToOTS(); // Over-the-shoulder aim mode + void changeCameraFromOTS(); // Exit OTS back to third person bool cameraThirdPerson() const { return (mCameraMode == CAMERA_MODE_THIRD_PERSON && mLastCameraMode == CAMERA_MODE_THIRD_PERSON); } - bool cameraMouselook() const { return (mCameraMode == CAMERA_MODE_MOUSELOOK && mLastCameraMode == CAMERA_MODE_MOUSELOOK); } + // Also true for OTS — reuses mouselook input and UI behaviour; camera position handled separately. + bool cameraMouselook() const { return (mCameraMode == CAMERA_MODE_MOUSELOOK && mLastCameraMode == CAMERA_MODE_MOUSELOOK) || mCameraMode == CAMERA_MODE_OTS; } bool cameraCustomizeAvatar() const { return (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR /*&& !mCameraAnimating*/); } bool cameraFollow() const { return (mCameraMode == CAMERA_MODE_FOLLOW && mLastCameraMode == CAMERA_MODE_FOLLOW); } + bool cameraOTS() const { return mCameraMode == CAMERA_MODE_OTS; } ECameraMode getCameraMode() const { return mCameraMode; } ECameraMode getLastCameraMode() const { return mLastCameraMode; } void updateCamera(); // Call once per frame to update camera location/orientation diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c74c0db08c..719447b920 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -136,10 +136,12 @@ #include "stringize.h" #include "llcoros.h" #include "llexception.h" -#if !_M_ARM64 // !LL_LINUX +#if defined(LL_CEF) #include "cef/dullahan_version.h" +#endif +#if defined(LL_VLC) #include "vlc/libvlc_version.h" -#endif // LL_LINUX +#endif #if LL_DARWIN #if LL_SDL @@ -3517,7 +3519,7 @@ LLSD LLAppViewer::getViewerInfo() const info["VOICE_VERSION"] = LLTrans::getString("NotConnected"); } -#if !_M_ARM64 // !LL_LINUX +#if defined(LL_CEF) std::ostringstream cef_ver_codec; cef_ver_codec << "Dullahan: "; cef_ver_codec << DULLAHAN_VERSION_MAJOR; @@ -3547,7 +3549,7 @@ LLSD LLAppViewer::getViewerInfo() const info["LIBCEF_VERSION"] = "Undefined"; #endif -#if !_M_ARM64 // !LL_LINUX +#if defined(LL_VLC) std::ostringstream vlc_ver_codec; vlc_ver_codec << LIBVLC_VERSION_MAJOR; vlc_ver_codec << "."; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 5bbaed750c..728a8ef81e 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -131,16 +131,12 @@ int main( int argc, char **argv ) // install unexpected exception handler gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); -#ifdef __aarch64__ - setenv("LD_PRELOAD", APP_PLUGIN_DIR"/libcef.so", 1); -#else # if LL_LINUX setenv("LD_PRELOAD", "libpthread.so.0 libGL.so.1", 1); # else setenv("LD_PRELOAD", "libpthread.so libGL.so.1", 1); # endif setenv("__GL_THREADED_OPTIMIZATIONS", "1", 0); -#endif bool ok = viewer_app_ptr->init(); if(!ok) diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index fb1426a235..c6b17fcb4e 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -34,6 +34,7 @@ #include "llnotifications.h" #include "llnotificationsutil.h" #include "roles_constants.h" // for GP_MEMBER_INVITE +#include "llregionflags.h" // for ESTATE_ACCESS_BANNED_AGENT_ADD #include "llagent.h" #include "llappviewer.h" // for gLastVersionChannel @@ -625,6 +626,34 @@ void LLAvatarActions::ejectAvatar(const LLUUID& id, bool ban_enabled) } // static +void LLAvatarActions::estateKickAvatar(const LLUUID& id) +{ + LLAvatarName av_name; + LLSD payload; + payload["avatar_id"] = id; + LLSD args; + if (LLAvatarNameCache::get(id, &av_name)) + { + args["EVIL_USER"] = av_name.getCompleteName(); + } + LLNotificationsUtil::add("EstateKickUser", args, payload, handleEstateKickAvatar); +} + +// static +void LLAvatarActions::estateBanAvatar(const LLUUID& id) +{ + LLAvatarName av_name; + LLSD payload; + payload["avatar_id"] = id; + LLSD args; + if (LLAvatarNameCache::get(id, &av_name)) + { + args["AVATAR_NAME"] = av_name.getCompleteName(); + } + LLNotificationsUtil::add("EstateBanUser", args, payload, handleEstateBanAvatar); +} + +// static void LLAvatarActions::freeze(const LLUUID& id) { LLSD payload; @@ -1425,6 +1454,62 @@ bool LLAvatarActions::handleEjectAvatar(const LLSD& notification, const LLSD& re return false; } +bool LLAvatarActions::handleEstateKickAvatar(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); + msg->nextBlock("MethodData"); + msg->addString("Method", "kickestate"); + msg->addUUID("Invoice", LLUUID::generateNewID()); + msg->nextBlock("ParamList"); + msg->addString("Parameter", avatar_id.asString()); + gAgent.sendReliableMessage(); + } + return false; +} + +bool LLAvatarActions::handleEstateBanAvatar(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); + msg->nextBlock("MethodData"); + msg->addString("Method", "estateaccessdelta"); + msg->addUUID("Invoice", LLUUID::generateNewID()); + + std::string buf; + gAgent.getID().toString(buf); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + buf = llformat("%u", (U32)ESTATE_ACCESS_BANNED_AGENT_ADD); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + avatar_id.toString(buf); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + gAgent.sendReliableMessage(); + } + return false; +} + bool LLAvatarActions::handleFreeze(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 1f5a42ed22..bc4eb6fa60 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -192,6 +192,10 @@ public: static void freezeAvatar(const LLUUID& id); static void ejectAvatar(const LLUUID& id, bool ban_enabled = false); + + static void estateKickAvatar(const LLUUID& id); + + static void estateBanAvatar(const LLUUID& id); /** * Kick avatar off grid */ @@ -263,6 +267,8 @@ private: static bool handlePay(const LLSD& notification, const LLSD& response, LLUUID avatar_id); static bool handleFreezeAvatar(const LLSD& notification, const LLSD& response); static bool handleEjectAvatar(const LLSD& notification, const LLSD& response); + static bool handleEstateKickAvatar(const LLSD& notification, const LLSD& response); + static bool handleEstateBanAvatar(const LLSD& notification, const LLSD& response); static bool handleKick(const LLSD& notification, const LLSD& response); static bool handleFreeze(const LLSD& notification, const LLSD& response); static bool handleUnfreeze(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 63ec43458b..a2a0731256 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -48,6 +48,8 @@ #include "llagentcamera.h" #include "llappviewer.h" // for gDisconnected #include "llavataractions.h" +#include "llgroupcolormap.h" // group-based dot tinting +#include "llvoavatar.h" // group-based dot tinting #include "llcallingcard.h" // LLAvatarTracker #include "llfloaterland.h" #include "llfloaterworldmap.h" @@ -432,6 +434,24 @@ void LLNetMap::draw() LLColor4 color = LLAvatarActions::isFriend(uuid) ? map_avatar_friend_color : map_avatar_color; + // Group-based dot tinting: override with group color if one is set. + // Look up the avatar's active group UUID from the LLVOAvatar object. + if (LLViewerObject* obj = gObjectList.findObject(uuid)) + { + if (LLVOAvatar* av = dynamic_cast<LLVOAvatar*>(obj)) + { + LLUUID active_group = av->getActiveGroupID(); + if (active_group.notNull()) + { + LLColor4 group_color = LLGroupColorMap::getInstance()->getGroupColor(active_group); + if (group_color.mV[VW] >= 0.01f) + { + color = group_color; + } + } + } + } + unknown_relative_z = sorted_positions[i].mdV[VZ] >= COARSEUPDATE_MAX_Z && camera_position.mV[VZ] >= COARSEUPDATE_MAX_Z; @@ -505,10 +525,23 @@ void LLNetMap::draw() LLUIImagePtr you = LLWorldMapView::sAvatarYouLargeImage; if (you) { + // Group-based dot tinting for self: use gAgent.getGroupID() directly + LLColor4 self_color = UI_VERTEX_COLOR; + LLUUID self_group = gAgent.getGroupID(); + if (self_group.notNull()) + { + LLColor4 group_color = LLGroupColorMap::getInstance()->getGroupColor(self_group); + if (group_color.mV[VW] >= 0.01f) + { + self_color = group_color; + } + } + you->draw(ll_round(pos_map.mV[VX] - mDotRadius), ll_round(pos_map.mV[VY] - mDotRadius), dot_width, - dot_width); + dot_width, + self_color); F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2((F32)local_mouse_x, (F32)local_mouse_y)); diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index 794ae4ad44..537ea28a4d 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -84,11 +84,14 @@ LLContextMenu* PeopleContextMenu::createMenu() registrar.add("Avatar.Calllog", boost::bind(&LLAvatarActions::viewChatHistory, id)); registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::freezeAvatar, id)); registrar.add("Avatar.Eject", boost::bind(&PeopleContextMenu::eject, this)); + registrar.add("Avatar.EstateKick", boost::bind(&LLAvatarActions::estateKickAvatar, id)); + registrar.add("Avatar.EstateBan", boost::bind(&LLAvatarActions::estateBanAvatar, id)); enable_registrar.add("Avatar.EnableItem", boost::bind(&PeopleContextMenu::enableContextMenuItem, this, _2)); enable_registrar.add("Avatar.CheckItem", boost::bind(&PeopleContextMenu::checkContextMenuItem, this, _2)); enable_registrar.add("Avatar.EnableFreezeEject", boost::bind(&PeopleContextMenu::enableFreezeEject, this, _2)); + enable_registrar.add("Avatar.EnableEstateEjectBan", boost::bind(&PeopleContextMenu::enableEstateEjectBan, this, _2)); // create the context menu from the XUI menu = createFromFile("menu_people_nearby.xml"); @@ -318,6 +321,17 @@ bool PeopleContextMenu::enableFreezeEject(const LLSD& userdata) return new_value; } +bool PeopleContextMenu::enableEstateEjectBan(const LLSD& userdata) +{ + if (gAgent.getID() == mUUIDs.front() || mUUIDs.size() != 1) + return false; + + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return false; + if (gAgent.isGodlike()) return true; + return region->getOwner() == gAgent.getID() || region->isEstateManager(); +} + void PeopleContextMenu::requestTeleport() { // boost::bind cannot recognize overloaded method LLAvatarActions::teleportRequest(), @@ -419,6 +433,8 @@ void NearbyPeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags) items.push_back(std::string("block_unblock")); items.push_back(std::string("freeze")); items.push_back(std::string("eject")); + items.push_back(std::string("estate_eject")); + items.push_back(std::string("estate_ban")); } hide_context_entries(menu, items, disabled_items); diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index ad38cebc31..ad6a26c645 100644 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -47,6 +47,7 @@ private: bool enableContextMenuItem(const LLSD& userdata); bool checkContextMenuItem(const LLSD& userdata); bool enableFreezeEject(const LLSD& userdata); + bool enableEstateEjectBan(const LLSD& userdata); void offerTeleport(); void eject(); void startConference(); diff --git a/indra/newview/llquickprefs.cpp b/indra/newview/llquickprefs.cpp index 800aa7abac..9e83857a15 100644 --- a/indra/newview/llquickprefs.cpp +++ b/indra/newview/llquickprefs.cpp @@ -26,6 +26,8 @@ #include "llquickprefs.h" #include "llagent.h" +#include "llagentcamera.h" +#include "llcheckboxctrl.h" #include "llsliderctrl.h" #include "lltextbox.h" #include "llviewercontrol.h" @@ -97,6 +99,14 @@ bool LLFloaterQuickPrefs::postBuild() } onRegionChanged(); // evaluate current region immediately + // OTS aim mode checkbox + mOTSEnabledCheck = getChild<LLCheckBoxCtrl>("ots_enabled"); + if (mOTSEnabledCheck) + { + mOTSEnabledCheck->setCommitCallback( + boost::bind(&LLFloaterQuickPrefs::onOTSEnabledChanged, this)); + } + return true; } @@ -203,3 +213,16 @@ void LLFloaterQuickPrefs::syncAvatarZOffsetFromPreferenceSetting() F32 value = gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ"); mAvatarZOffsetSlider->setValue(value, false); // false = no commit signal } + +void LLFloaterQuickPrefs::onOTSEnabledChanged() +{ + if (mOTSEnabledCheck) + { + gSavedSettings.setBOOL("OTSEnabled", mOTSEnabledCheck->get()); + // If currently in OTS mode and checkbox was unchecked, exit OTS + if (!mOTSEnabledCheck->get() && gAgentCamera.cameraOTS()) + { + gAgentCamera.changeCameraFromOTS(); + } + } +} diff --git a/indra/newview/llquickprefs.h b/indra/newview/llquickprefs.h index 0ef56a4299..b90333831c 100644 --- a/indra/newview/llquickprefs.h +++ b/indra/newview/llquickprefs.h @@ -27,6 +27,7 @@ #include "llfloater.h" class LLSliderCtrl; +class LLCheckBoxCtrl; class LLTextBox; /** @@ -76,6 +77,10 @@ private: void syncAvatarZOffsetFromPreferenceSetting(); boost::signals2::connection mRegionChangedSlot; + + // OTS over-the-shoulder aim + LLCheckBoxCtrl* mOTSEnabledCheck { nullptr }; + void onOTSEnabledChanged(); }; #endif // LL_LLQUICKPREFS_H diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 7d97151e9d..59dc4319e1 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -280,6 +280,12 @@ static void update_tp_display(bool minimized) F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count; F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32(); F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time); + + // Reuse the minimized-window path to suppress the teleport progress screen. + if (gSavedSettings.getBOOL("DisableTeleportScreens")) + { + minimized = true; + } if (gAgent.getTeleportState() != LLAgent::TELEPORT_START && teleport_percent > 100.f) { // Give up. Don't keep the UI locked forever. diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6448dd6ba5..66ca722b88 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1826,7 +1826,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ if (plugin_basename == "media_plugin_cef") { launcher_name = "/compat/linux/usr/libexec/megapahit/SLPlugin"; - plugin_name = "/compat/linux/usr/lib/x86_64-linux-gnu/libmedia_plugin_cef.so"; + plugin_name = "/compat/linux/usr/lib/x86_64-linux-gnu/megapahit/libmedia_plugin_cef.so"; } #endif @@ -1891,8 +1891,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ std::string plugin_dir = gDirUtilp->getLLPluginDir(); if (plugin_basename == "media_plugin_cef") { - plugin_dir = "/compat/linux/usr/lib/x86_64-linux-gnu"; - plugin_name = "/usr/lib/x86_64-linux-gnu/libmedia_plugin_cef.so"; + plugin_dir = "/compat/linux/usr/lib/x86_64-linux-gnu/megapahit"; + plugin_name = "/usr/lib/x86_64-linux-gnu/megapahit/libmedia_plugin_cef.so"; } #else const std::string plugin_dir = gDirUtilp->getLLPluginDir(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4632800e2d..1b1d703f38 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -4065,6 +4065,44 @@ void handle_avatar_eject(const LLSD& avatar_id) } } +void handle_avatar_estate_kick(const LLSD& avatar_id) +{ + LLUUID id = avatar_id.asUUID(); + if (id.isNull()) + { + LLVOAvatar* avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) id = avatar->getID(); + } + if (id.notNull()) + { + LLAvatarActions::estateKickAvatar(id); + } +} + +void handle_avatar_estate_ban(const LLSD& avatar_id) +{ + LLUUID id = avatar_id.asUUID(); + if (id.isNull()) + { + LLVOAvatar* avatar = find_avatar_from_object( + LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) id = avatar->getID(); + } + if (id.notNull()) + { + LLAvatarActions::estateBanAvatar(id); + } +} + +bool enable_estate_eject_ban(const LLSD& avatar_id) +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return false; + if (gAgent.isGodlike()) return true; + return region->getOwner() == gAgent.getID() || region->isEstateManager(); +} + bool my_profile_visible() { LLFloater* floaterp = LLAvatarActions::getProfileFloater(gAgentID); @@ -4778,25 +4816,37 @@ class LLViewMouselook : public view_listener_t { bool handleEvent(const LLSD& userdata) { + // When OTS is enabled M toggles OTS mode (shoulder cam). + // When disabled M toggles normal first-person mouselook. + if (gSavedSettings.getBOOL("OTSEnabled")) + { + if (!gAgentCamera.cameraOTS()) + { + gAgentCamera.changeCameraToOTS(); + } + else + { + gAgentCamera.changeCameraFromOTS(); + } + return true; + } + if (!gAgentCamera.cameraMouselook()) { gAgentCamera.changeCameraToMouselook(); } else { - // NaCl: Right-click + scroll wheel zoom in mouselook (ported from Firestorm). - // If we were zoomed when the user toggles out of mouselook, restore the - // normal (pre-zoom) FOV before switching back to the default camera. + // NaCl: restore FOV on mouselook exit LLVector3 mlFovValues = gSavedSettings.getVector3("_NACL_MLFovValues"); F32 cameraAngle = gSavedSettings.getF32("CameraAngle"); if (mlFovValues.mV[VZ] > 0.0f) { - mlFovValues.mV[VY] = cameraAngle; // preserve last zoomed FOV + mlFovValues.mV[VY] = cameraAngle; mlFovValues.mV[VZ] = 0.0f; gSavedSettings.setVector3("_NACL_MLFovValues", mlFovValues); - gSavedSettings.setF32("CameraAngle", mlFovValues.mV[VX]); // restore normal FOV + gSavedSettings.setF32("CameraAngle", mlFovValues.mV[VX]); } - // NaCl End gAgentCamera.changeCameraToDefault(); } return true; @@ -10346,6 +10396,9 @@ void initialize_menus() view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); + commit.add("Avatar.EstateKick", boost::bind(&handle_avatar_estate_kick, _2)); + commit.add("Avatar.EstateBan", boost::bind(&handle_avatar_estate_ban, _2)); + enable.add("Avatar.EnableEstateEjectBan", boost::bind(&enable_estate_eject_ban, _2)); commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b8515fd92b..1c6544f3f9 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -6120,11 +6120,18 @@ void process_teleport_local(LLMessageSystem *msg,void**) } gAgent.setPositionAgent(pos); - gAgentCamera.slamLookAt(look_at); + + bool keep_camera_local_tp = gSavedSettings.getBOOL("KeepCameraOnLocalTeleport"); + + if (!keep_camera_local_tp) + { + gAgentCamera.slamLookAt(look_at); + } if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) ) { - gAgentCamera.resetView(true, true); + // resetView still runs (cleanup); the false args just leave the camera alone. + gAgentCamera.resetView(!keep_camera_local_tp, !keep_camera_local_tp); } // send camera update to new region diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 70e31363ff..0c3b82c886 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -298,6 +298,7 @@ public: // LLAvatarPropertiesObserver: receives APT_GROUPS reply for group-tint lookup /*virtual*/ void processProperties(void* data, EAvatarProcessorType type) override; void sendAvatarGroupsRequest(); + const LLUUID& getActiveGroupID() const { return mActiveGroupID; } static void invalidateNameTag(const LLUUID& agent_id); // force all name tags to rebuild, useful when display names turned on/off static void invalidateNameTags(); diff --git a/indra/newview/skins/default/xui/en/floater_quick_prefs.xml b/indra/newview/skins/default/xui/en/floater_quick_prefs.xml index 8b20fda6f5..f5bdcf2156 100644 --- a/indra/newview/skins/default/xui/en/floater_quick_prefs.xml +++ b/indra/newview/skins/default/xui/en/floater_quick_prefs.xml @@ -9,7 +9,7 @@ can_minimize="true" can_close="true" can_resize="false" - height="96" + height="240" width="320" layout="topleft" name="quick_prefs" @@ -82,4 +82,128 @@ name="max_bandwidth" tool_tip="Network bandwidth in Kbps (50 – 3000)" /> + <view_border + follows="left|right" + layout="topleft" + left="2" + right="-2" + top_pad="10" + height="2" + name="ots_divider" /> + + <text + type="string" + follows="left|top" + height="16" + layout="topleft" + left="5" + top_pad="6" + width="290" + text_color="EmphasisColor" + name="OTSLabel"> + Over-the-Shoulder Cam: + </text> + + <check_box + control_name="OTSEnabled" + follows="left|top" + height="16" + label="Use Over-The-Shoulder Cam" + layout="topleft" + left="10" + top_pad="4" + width="290" + name="ots_enabled" + tool_tip="When checked, M enters shoulder cam instead of first-person mouselook" /> + + <text + type="string" + follows="left|top" + height="16" + layout="topleft" + left="10" + top_pad="6" + width="100" + name="OTSDistLabel"> + Distance: + </text> + + <slider + control_name="OTSCameraDistance" + decimal_digits="1" + can_edit_text="true" + follows="left|right|top" + height="16" + increment="0.1" + initial_value="3.0" + max_val="10.0" + min_val="1.0" + label_width="0" + layout="topleft" + left="110" + right="-10" + top_delta="-2" + name="ots_distance" + tool_tip="Camera distance behind avatar (1 – 10 m)" /> + + <text + type="string" + follows="left|top" + height="16" + layout="topleft" + left="10" + top_pad="4" + width="100" + name="OTSSideLabel"> + Side offset: + </text> + + <slider + control_name="OTSCameraSide" + decimal_digits="2" + can_edit_text="true" + follows="left|right|top" + height="16" + increment="0.05" + initial_value="-0.5" + max_val="1.0" + min_val="-1.0" + label_width="0" + layout="topleft" + left="110" + right="-10" + top_delta="-2" + name="ots_side" + tool_tip="Side offset: negative = right shoulder, positive = left shoulder" /> + + <text + type="string" + follows="left|top" + height="16" + layout="topleft" + left="10" + top_pad="4" + width="100" + name="OTSHeightLabel"> + Height: + </text> + + <slider + control_name="OTSCameraHeight" + decimal_digits="2" + can_edit_text="true" + follows="left|right|top" + height="16" + increment="0.05" + initial_value="0.5" + max_val="2.0" + min_val="0.0" + label_width="0" + layout="topleft" + left="110" + right="-10" + top_delta="-2" + name="ots_height" + tool_tip="Camera height above avatar root (0 – 2 m)" /> + </floater> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml index fc4ffde947..f86e9160ed 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml @@ -90,6 +90,22 @@ function="Avatar.EnableFreezeEject"/> </menu_item_call> <menu_item_call + label="Estate Eject" + name="EstateEject..."> + <menu_item_call.on_click + function="Avatar.EstateKick" /> + <menu_item_call.on_visible + function="Avatar.EnableEstateEjectBan"/> + </menu_item_call> + <menu_item_call + label="Estate Ban" + name="EstateBan..."> + <menu_item_call.on_click + function="Avatar.EstateBan" /> + <menu_item_call.on_visible + function="Avatar.EnableEstateEjectBan"/> + </menu_item_call> + <menu_item_call label="Debug Textures" name="Debug..."> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby.xml b/indra/newview/skins/default/xui/en/menu_people_nearby.xml index b7a296bf31..8d73eee60a 100644 --- a/indra/newview/skins/default/xui/en/menu_people_nearby.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby.xml @@ -169,4 +169,20 @@ <menu_item_call.on_visible function="Avatar.EnableFreezeEject"/> </menu_item_call> + <menu_item_call + label="Estate Eject" + name="estate_eject"> + <menu_item_call.on_click + function="Avatar.EstateKick" /> + <menu_item_call.on_visible + function="Avatar.EnableEstateEjectBan"/> + </menu_item_call> + <menu_item_call + label="Estate Ban" + name="estate_ban"> + <menu_item_call.on_click + function="Avatar.EstateBan" /> + <menu_item_call.on_visible + function="Avatar.EnableEstateEjectBan"/> + </menu_item_call> </context_menu> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index facf9b7e46..65f26d50e7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5404,6 +5404,18 @@ Kick [EVIL_USER] from this estate? <notification icon="alertmodal.tga" + name="EstateBanUser" + type="alertmodal"> +Ban [AVATAR_NAME] from this estate? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Ban"/> + </notification> + + <notification + icon="alertmodal.tga" name="EstateChangeCovenant" type="alertmodal"> Are you sure you want to change the Estate Covenant? diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml index eee55bd7bc..ad24451e24 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml @@ -9,317 +9,450 @@ name="move_panel" top="1" width="517"> - <icon - follows="left|top" - height="18" - image_name="Cam_FreeCam_Off" - layout="topleft" - name="camera_icon" - mouse_opaque="false" - visible="true" - width="18" - left="30" - top="10"/> - <slider - can_edit_text="true" - control_name="CameraAngle" - decimal_digits="2" - follows="left|top" - height="16" - increment="0.025" - initial_value="1.57" - layout="topleft" - label_width="100" - label="View angle" - left_pad="30" - max_val="2.97" - min_val="0.17" - name="camera_fov" - show_text="false" - width="240" /> - <slider - can_edit_text="true" - control_name="CameraOffsetScale" - decimal_digits="2" - follows="left|top" - height="16" - increment="0.025" - initial_value="1" - layout="topleft" - label="Distance" + + <tab_container + name="move_view_tab_container" + enabled="true" + top_pad="0" + follows="left|top|right|bottom" + width="517" + height="408" left_delta="0" - label_width="100" - max_val="3" - min_val="0.5" - name="camera_offset_scale" - show_text="false" - width="240" - top_pad="5"/> - <text - follows="left|top" - type="string" - length="1" - height="10" - left="80" - name="heading2" - width="270" - top_pad="5"> - Automatic position for: - </text> - <check_box - control_name="EditCameraMovement" - height="20" - follows="left|top" - label="Build/Edit" + tab_position="top" + tab_stop="false"> + + <!-- ── Move & View tab (existing content) ─────────────────────────── --> + <panel + label="Move & View" + name="move_view_panel" layout="topleft" - left_delta="30" - name="edit_camera_movement" - tool_tip="Use automatic camera positioning when entering and exiting edit mode" - width="280" - top_pad="5" /> - <check_box - control_name="AppearanceCameraMovement" - follows="left|top" - height="16" - label="Appearance" - layout="topleft" - name="appearance_camera_movement" - tool_tip="Use automatic camera positioning while in edit mode" - width="242" /> - <icon - follows="left|top" - height="18" - image_name="Move_Walk_Off" - layout="topleft" - name="avatar_icon" - mouse_opaque="false" - visible="true" - width="18" - top_pad="10" - left="30" /> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="78" - name="keyboard_lbl" - width="270" - top_delta="2"> - Keyboard: - </text> - <check_box - control_name="ArrowKeysAlwaysMove" - follows="left|top" - height="20" - label="Arrow keys always move me while in chat" - layout="topleft" - left_delta="5" - name="arrow_keys_move_avatar_check" - width="237" - top_pad="5"/> - <check_box - control_name="AllowTapTapHoldRun" - follows="left|top" - height="20" - label="Tap-tap-hold to run" - layout="topleft" - left_delta="0" - name="tap_tap_hold_to_run" - width="237" - top_pad="0"/> - <check_box - control_name="AutomaticFly" - follows="left|top" - height="20" - label="Hold jump or crouch key to start or stop flying" - layout="topleft" - left_delta="0" - name="automatic_fly" - width="237" - top_pad="0"/> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="78" - name="mouse_lbl" - width="270" - top_pad="15"> - Mouse: - </text> - <check_box - control_name="FirstPersonAvatarVisible" - follows="left|top" - height="20" - label="Show me in Mouselook" - layout="topleft" - left_delta="5" - name="first_person_avatar_visible" - top_pad="5" - width="256" /> - <text - type="string" - length="1" - follows="left|top" - height="15" - layout="topleft" - left_delta="3" - name=" Mouse Sensitivity" - top_pad="10" - width="160" - wrap="true"> - Mouselook mouse sensitivity: - </text> - <slider - control_name="MouseSensitivity" - follows="left|top" - height="15" - initial_value="2" - layout="topleft" - show_text="false" - left_pad="0" - max_val="15" - name="mouse_sensitivity" - top_delta="-1" - width="115" /> - <check_box - control_name="InvertMouse" - height="16" - label="Invert" - layout="topleft" - left_pad="2" - name="invert_mouse" - top_delta="0" - width="128" /> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="86" - name="mouse_warp_lbl" - width="150" - top_pad="20"> - Mouse Warp: - </text> - <combo_box - control_name="MouseWarpMode" - height="23" - layout="topleft" - left_pad="10" - top_delta="-6" - name="mouse_warp_combo" - tool_tip="Controls warping of the mouse to the center of the screen during alt-zoom and mouse look." - width="200"> - <combo_box.item - label="Automatic" - name="0" - value="0"/> - <combo_box.item - label="On" - name="1" - value="1"/> - <combo_box.item - label="Off" - name="2" - value="2"/> - </combo_box> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="86" - name="single_click_action_lbl" - width="150" - top_pad="12"> - Single click on land: - </text> - <combo_box - height="23" - layout="topleft" - left_pad="10" - top_delta="-6" - name="single_click_action_combo" - width="200"> - <combo_box.item - label="No action" - name="0" - value="0"/> - <combo_box.item - label="Move to clicked point" - name="1" - value="1"/> - <combo_box.commit_callback - function="Pref.ClickActionChange"/> - </combo_box> - <text - follows="left|top" - type="string" - length="1" - height="10" - layout="topleft" - left="86" - name="double_click_action_lbl" - width="150" - top_pad="12"> - Double click on land: - </text> - <combo_box - height="23" - layout="topleft" - left_pad="10" - top_delta="-6" - name="double_click_action_combo" - width="200"> - <combo_box.item - label="No action" - name="0" - value="0"/> - <combo_box.item - label="Move to clicked point" - name="1" - value="1"/> - <combo_box.item - label="Teleport to clicked point" - name="2" - value="2"/> - <combo_box.commit_callback - function="Pref.ClickActionChange"/> - </combo_box> - <check_box - control_name="EnableCollisionSounds" - height="20" - label="Play sound on collisions" - layout="topleft" - left="83" - name="sound_on_collisions" - top_pad="0" - width="200" /> - <check_box - control_name="DoubleClickZoomIn" - height="20" - label="Double click on nearby list to zoom in on avatar" - layout="topleft" - left="83" - name="double_click_zoom_in" - top_pad="0" - width="200" /> - <button - height="23" - label="Other Devices" - left="30" - name="joystick_setup_button" - top="30" - width="155"> - <button.commit_callback - function="Floater.Show" - parameter="pref_joystick" /> - </button> + follows="top|left"> + + <icon + follows="left|top" + height="18" + image_name="Cam_FreeCam_Off" + layout="topleft" + name="camera_icon" + mouse_opaque="false" + visible="true" + width="18" + left="30" + top="10"/> + <slider + can_edit_text="true" + control_name="CameraAngle" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.025" + initial_value="1.57" + layout="topleft" + label_width="100" + label="View angle" + left_pad="30" + max_val="2.97" + min_val="0.17" + name="camera_fov" + show_text="false" + width="240" /> + <slider + can_edit_text="true" + control_name="CameraOffsetScale" + decimal_digits="2" + follows="left|top" + height="16" + increment="0.025" + initial_value="1" + layout="topleft" + label="Distance" + left_delta="0" + label_width="100" + max_val="3" + min_val="0.5" + name="camera_offset_scale" + show_text="false" + width="240" + top_pad="5"/> + <text + follows="left|top" + type="string" + length="1" + height="10" + left="80" + name="heading2" + width="270" + top_pad="5"> + Automatic position for: + </text> + <check_box + control_name="EditCameraMovement" + height="20" + follows="left|top" + label="Build/Edit" + layout="topleft" + left_delta="30" + name="edit_camera_movement" + tool_tip="Use automatic camera positioning when entering and exiting edit mode" + width="280" + top_pad="5" /> + <check_box + control_name="AppearanceCameraMovement" + follows="left|top" + height="16" + label="Appearance" + layout="topleft" + name="appearance_camera_movement" + tool_tip="Use automatic camera positioning while in edit mode" + width="242" /> + <icon + follows="left|top" + height="18" + image_name="Move_Walk_Off" + layout="topleft" + name="avatar_icon" + mouse_opaque="false" + visible="true" + width="18" + top_pad="10" + left="30" /> + <text + follows="left|top" + type="string" + length="1" + height="10" + layout="topleft" + left="78" + name="keyboard_lbl" + width="270" + top_delta="2"> + Keyboard: + </text> + <check_box + control_name="ArrowKeysAlwaysMove" + follows="left|top" + height="20" + label="Arrow keys always move me while in chat" + layout="topleft" + left_delta="5" + name="arrow_keys_move_avatar_check" + width="237" + top_pad="5"/> + <check_box + control_name="AllowTapTapHoldRun" + follows="left|top" + height="20" + label="Tap-tap-hold to run" + layout="topleft" + left_delta="0" + name="tap_tap_hold_to_run" + width="237" + top_pad="0"/> + <check_box + control_name="AutomaticFly" + follows="left|top" + height="20" + label="Hold jump or crouch key to start or stop flying" + layout="topleft" + left_delta="0" + name="automatic_fly" + width="237" + top_pad="0"/> + <text + follows="left|top" + type="string" + length="1" + height="10" + layout="topleft" + left="78" + name="mouse_lbl" + width="270" + top_pad="15"> + Mouse: + </text> + <check_box + control_name="FirstPersonAvatarVisible" + follows="left|top" + height="20" + label="Show me in Mouselook" + layout="topleft" + left_delta="5" + name="first_person_avatar_visible" + top_pad="5" + width="256" /> + <text + type="string" + length="1" + follows="left|top" + height="15" + layout="topleft" + left_delta="3" + name=" Mouse Sensitivity" + top_pad="10" + width="160" + wrap="true"> + Mouselook mouse sensitivity: + </text> + <slider + control_name="MouseSensitivity" + follows="left|top" + height="15" + initial_value="2" + layout="topleft" + show_text="false" + left_pad="0" + max_val="15" + name="mouse_sensitivity" + top_delta="-1" + width="115" /> + <check_box + control_name="InvertMouse" + height="16" + label="Invert" + layout="topleft" + left_pad="2" + name="invert_mouse" + top_delta="0" + width="128" /> + <text + follows="left|top" + type="string" + length="1" + height="10" + layout="topleft" + left="86" + name="mouse_warp_lbl" + width="150" + top_pad="20"> + Mouse Warp: + </text> + <combo_box + control_name="MouseWarpMode" + height="23" + layout="topleft" + left_pad="10" + top_delta="-6" + name="mouse_warp_combo" + tool_tip="Controls warping of the mouse to the center of the screen during alt-zoom and mouse look." + width="200"> + <combo_box.item label="Automatic" name="0" value="0"/> + <combo_box.item label="On" name="1" value="1"/> + <combo_box.item label="Off" name="2" value="2"/> + </combo_box> + <text + follows="left|top" + type="string" + length="1" + height="10" + layout="topleft" + left="86" + name="single_click_action_lbl" + width="150" + top_pad="12"> + Single click on land: + </text> + <combo_box + height="23" + layout="topleft" + left_pad="10" + top_delta="-6" + name="single_click_action_combo" + width="200"> + <combo_box.item label="No action" name="0" value="0"/> + <combo_box.item label="Move to clicked point" name="1" value="1"/> + <combo_box.commit_callback function="Pref.ClickActionChange"/> + </combo_box> + <text + follows="left|top" + type="string" + length="1" + height="10" + layout="topleft" + left="86" + name="double_click_action_lbl" + width="150" + top_pad="12"> + Double click on land: + </text> + <combo_box + height="23" + layout="topleft" + left_pad="10" + top_delta="-6" + name="double_click_action_combo" + width="200"> + <combo_box.item label="No action" name="0" value="0"/> + <combo_box.item label="Move to clicked point" name="1" value="1"/> + <combo_box.item label="Teleport to clicked point" name="2" value="2"/> + <combo_box.commit_callback function="Pref.ClickActionChange"/> + </combo_box> + <check_box + control_name="EnableCollisionSounds" + height="20" + label="Play sound on collisions" + layout="topleft" + left="83" + name="sound_on_collisions" + top_pad="0" + width="200" /> + <check_box + control_name="DoubleClickZoomIn" + height="20" + label="Double click on nearby list to zoom in on avatar" + layout="topleft" + left="83" + name="double_click_zoom_in" + top_pad="0" + width="200" /> + <button + height="23" + label="Other Devices" + left="30" + name="joystick_setup_button" + top="30" + width="155"> + <button.commit_callback function="Floater.Show" parameter="pref_joystick" /> + </button> + + </panel> + + <!-- ── Over-The-Shoulder tab ──────────────────────────────────────── --> + <panel + label="Over-The-Shoulder" + name="ots_panel" + layout="topleft" + follows="top|left"> + + <text + type="string" + follows="left|top" + font="SansSerifSmallBold" + height="20" + layout="topleft" + left="10" + name="ots_enable_header" + top="10" + width="490"> + Over-the-Shoulder Camera + </text> + + <check_box + control_name="OTSEnabled" + follows="left|top" + height="20" + label="Use Over-The-Shoulder Cam" + layout="topleft" + left="15" + name="ots_enabled_pref" + top_pad="5" + tool_tip="When checked, pressing M enters over-the-shoulder cam instead of first-person mouselook" + width="350" /> + + <text + type="string" + follows="left|top" + font="SansSerifSmallBold" + height="20" + layout="topleft" + left="10" + name="ots_pos_header" + top_pad="12" + width="490"> + Camera Position + </text> + + <text type="string" follows="left|top" height="16" layout="topleft" + left="15" top_pad="6" width="130" name="dist_label">Distance:</text> + <slider + control_name="OTSCameraDistance" + decimal_digits="1" can_edit_text="true" + follows="left|right|top" height="16" + increment="0.1" initial_value="3.0" max_val="10.0" min_val="1.0" + label_width="0" layout="topleft" left="150" right="-10" top_delta="-2" + name="ots_distance" + tool_tip="Camera distance behind avatar (1 – 10 m)" /> + + <text type="string" follows="left|top" height="16" layout="topleft" + left="15" top_pad="6" width="130" name="side_label">Side offset:</text> + <slider + control_name="OTSCameraSide" + decimal_digits="2" can_edit_text="true" + follows="left|right|top" height="16" + increment="0.05" initial_value="-0.5" max_val="1.0" min_val="-1.0" + label_width="0" layout="topleft" left="150" right="-10" top_delta="-2" + name="ots_side" + tool_tip="Side offset: negative = right shoulder, positive = left shoulder" /> + + <text type="string" follows="left|top" height="16" layout="topleft" + left="15" top_pad="6" width="130" name="height_label">Height:</text> + <slider + control_name="OTSCameraHeight" + decimal_digits="2" can_edit_text="true" + follows="left|right|top" height="16" + increment="0.05" initial_value="0.5" max_val="2.0" min_val="0.0" + label_width="0" layout="topleft" left="150" right="-10" top_delta="-2" + name="ots_height" + tool_tip="Camera height above avatar root (0 – 2 m)" /> + + <text type="string" follows="left|top" height="16" layout="topleft" + left="15" top_pad="6" width="130" name="focus_label">Focus distance:</text> + <slider + control_name="OTSFocusDistance" + decimal_digits="1" can_edit_text="true" + follows="left|right|top" height="16" + increment="0.5" initial_value="10.0" max_val="30.0" min_val="2.0" + label_width="0" layout="topleft" left="150" right="-10" top_delta="-2" + name="ots_focus_dist" + tool_tip="Focus point distance along camera forward axis (2 – 30 m)" /> + + </panel> + + <!-- ── Teleports tab ──────────────────────────────────────────────── --> + <panel + label="Teleports" + name="teleports_panel" + layout="topleft" + follows="top|left"> + + <text + type="string" + follows="left|top" + font="SansSerifSmallBold" + height="20" + layout="topleft" + left="10" + name="teleport_header" + top="10" + width="490"> + Teleport Options + </text> + + <check_box + control_name="KeepCameraOnLocalTeleport" + follows="left|top" + height="20" + label="Keep camera position on local teleport" + layout="topleft" + left="15" + name="keep_camera_on_local_teleport" + top_pad="8" + tool_tip="When teleporting within the same region, do not reset the camera position or mode (stays in mouselook/over-the-shoulder)" + width="450" /> + + <check_box + control_name="DisableTeleportScreens" + follows="left|top" + height="20" + label="Disable teleport progress screen" + layout="topleft" + left="15" + name="disable_teleport_screens" + top_pad="6" + tool_tip="Do not show the fullscreen progress/black screen during teleports" + width="450" /> + + </panel> + + </tab_container> + </panel> |
