diff --git a/.github/workflows/master_build.yml b/.github/workflows/master_build.yml index 9ef4728cb0..824c279845 100644 --- a/.github/workflows/master_build.yml +++ b/.github/workflows/master_build.yml @@ -3,114 +3,60 @@ name: Master CI Build on: push: branches: - - master + - gha-master-ci +# FIXME: Change target branch to "master" before merging into "master" branch. env: - #APP_NAME: gpu-frame-player APP_NAME: interface BUILD_TYPE: Release - BUCKET_NAME: hifi-gh-builds + BUILD_NUMBER: ${{ github.run_number }} CI_BUILD: Github - CMAKE_BACKTRACE_URL: https://highfidelity.sp.backtrace.io:6098 - CMAKE_BACKTRACE_TOKEN: ${{ secrets.backtrace_token }} - CMAKE_BACKTRACE_SYMBOLS_TOKEN: ${{ secrets.backtrace_symbols_token }} GIT_COMMIT: ${{ github.sha }} - HIFI_VCPKG_BOOTSTRAP: true - LAUNCHER_HMAC_SECRET: ${{ secrets.launcher_hmac_secret }} - OCULUS_APP_ID: '${{ secrets.oculus_app_id }}' + # VCPKG did not build well on OSX disabling HIFI_VCPKG_BOOTSTRAP, which invokes a download to a working version of vcpkg + # HIFI_VCPKG_BOOTSTRAP: true RELEASE_TYPE: PRODUCTION - RELEASE_DYNAMODB_V2: ReleaseManager2-ReleaseQueue-prod + RELEASE_NUMBER: ${{ github.run_number }} STABLE_BUILD: 0 + UPLOAD_BUCKET: athena-public - - # OSX specific variables + # OSX-specific variables DEVELOPER_DIR: /Applications/Xcode_11.2.app/Contents/Developer MACOSX_DEPLOYMENT_TARGET: '10.11' - # WIN32 specific variables + # WIN-specific variables PreferredToolArchitecture: X64 -# Mac OS -#PLATFORM_CMAKE_GENERATOR=Xcode -#PLATFORM_BUILD_ARGUMENTS=--config Release --target package -#ARTIFACT_EXPRESSION=build/*.dmg,build/*.zip - -# Windows -#PLATFORM_CMAKE_GENERATOR=Visual Studio 15 2017 Win64 -#PLATFORM_BUILD_ARGUMENTS=--target package --config release -#ARTIFACT_EXPRESSION=build/*.exe,build/*.zip,*-symbols.zip - -# Ubuntu -#PLATFORM_CMAKE_GENERATOR=Unix Makefiles -#PLATFORM_BUILD_ARGUMENTS=--target all -- -j4 -#ARTIFACT_EXPRESSION=build/assignment-client/**,build/domain-server/**,build/ice-server/ice-server,build/tools/ice-client/ice-client,build/tools/ac-client/ac-client,build/tools/oven,build/ext/makefiles/nvtt/project/lib/**,build/ext/makefiles/quazip/project/lib/** - -# Android -# branch: master -# GA_TRACKING_ID: ${{ secrets.ga_tracking_id }} -# ANDROID_OAUTH_CLIENT_SECRET=${MASKED_ANDROID_OAUTH_CLIENT_SECRET_NIGHTLY} -# ANDROID_OAUTH_CLIENT_ID=6c7d2349c0614640150db37457a1f75dce98a28ffe8f14d47f6cfae4de5b262a -# ANDROID_OAUTH_REDIRECT_URI=https://dev-android-interface.highfidelity.com/auth -# branch: !master -# GA_TRACKING_ID=UA-39558647-11 -# ANDROID_OAUTH_CLIENT_SECRET=${MASKED_ANDROID_OAUTH_CLIENT_SECRET_RELEASE} -# ANDROID_OAUTH_CLIENT_ID= c1063ea5d0b0c405e0c9cd77351328e211a91496a3f25985a99e861f1661db1d -# ANDROID_OAUTH_REDIRECT_URI=https://android-interface.highfidelity.com/auth -# ARTIFACT_EXPRESSION=android/*.apk -# ANDROID_APK_NAME=HighFidelity-Beta-PR${RELEASE_NUMBER}-${GIT_COMMIT_SHORT}.apk -# ANDROID_BUILT_APK_NAME=interface-debug.apk -# ANDROID_APP=interface -# ANDROID_BUILD_DIR=debug -# ANDROID_BUILD_TARGET=assembleDebug -# STABLE_BUILD=0 - - - jobs: - generate_build_number: - runs-on: ubuntu-latest - steps: - - name: Generate build number - id: buildnumber - uses: highfidelity/build-number@v3 - with: - token: ${{secrets.github_token}} - - name: Upload build number - uses: actions/upload-artifact@v1 - with: - name: BUILD_NUMBER - path: BUILD_NUMBER - build: strategy: matrix: - os: [windows-latest, macOS-latest] - build_type: [full, client] - #os: [windows-latest, macOS-latest, ubuntu-latest] - # exclude: - # - os: ubuntu-latest - # build_type: client + os: [windows-latest, macOS-latest, ubuntu-18.04] + # build_type: [full, client] + build_type: [full] + include: + - os: ubuntu-18.04 + build_type: full + apt-dependencies: mesa-common-dev libegl1 libglvnd-dev libdouble-conversion1 libpulse0 + fail-fast: false runs-on: ${{matrix.os}} - needs: generate_build_number steps: - - name: Download build number - uses: actions/download-artifact@v1 - with: - name: BUILD_NUMBER - - name: Restore build number - id: buildnumber - uses: highfidelity/build-number@v3 - with: - output_name: RELEASE_NUMBER - - name: Configure Build Environment 1 + - name: Report Build Number + shell: bash + run: | + echo "Build number: $BUILD_NUMBER" + - name: Configure build environment 1 shell: bash id: buildenv1 run: | echo ::set-env name=UPLOAD_PREFIX::master echo ::set-env name=GIT_COMMIT_SHORT::`echo $GIT_COMMIT | cut -c1-7` + echo ::set-env name=JOB_NAME::"build (${{matrix.os}}, ${{matrix.build_type}})" # Linux build variables - if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then + if [[ "${{ matrix.os }}" = "ubuntu-"* ]]; then + echo ::set-env name=PYTHON_EXEC::python3 echo ::set-env name=INSTALLER_EXT::tgz + echo ::set-env name=CMAKE_BUILD_EXTRA::"-- -j3" + echo ::set-env name=CMAKE_EXTRA::"-DBUILD_TOOLS:BOOLEAN=FALSE -DHIFI_PYTHON_EXEC:FILEPATH=$(which python3)" fi # Mac build variables if [ "${{ matrix.os }}" = "macOS-latest" ]; then @@ -118,8 +64,8 @@ jobs: echo ::set-env name=ZIP_COMMAND::zip echo ::set-env name=ZIP_ARGS::-r echo ::set-env name=INSTALLER_EXT::dmg - echo ::set-env name=SYMBOL_REGEX::dSYM - echo "::set-output name=symbols_archive::${{ steps.buildnumber.outputs.build_number }}-${{ matrix.build_type }}-mac-symbols.zip" + echo ::set-env name=CMAKE_EXTRA::"-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -G Xcode" + echo "::set-output name=symbols_archive::${BUILD_NUMBER}-${{ matrix.build_type }}-mac-symbols.zip" fi # Windows build variables if [ "${{ matrix.os }}" = "windows-latest" ]; then @@ -127,40 +73,28 @@ jobs: echo ::set-env name=ZIP_COMMAND::7z echo ::set-env name=ZIP_ARGS::a echo ::set-env name=INSTALLER_EXT::exe + echo ::set-env name=CMAKE_EXTRA::"-A x64" echo "::set-env name=SYMBOL_REGEX::\(exe\|dll\|pdb\)" - echo "::set-output name=symbols_archive::${{ steps.buildnumber.outputs.build_number }}-${{ matrix.build_type }}-win-symbols.zip" + echo "::set-output name=symbols_archive::${BUILD_NUMBER}-${{ matrix.build_type }}-win-symbols.zip" + # echo ::set-env name=HF_PFX_PASSPHRASE::${{secrets.pfx_key}} + # echo "::set-env name=HF_PFX_FILE::${{runner.workspace}}\build\codesign.pfx" fi # Configuration is broken into two steps because you can't set an env var and also reference it in the same step - - name: Configure Build Environment 2 + - name: Configure build environment 2 shell: bash run: | echo "${{ steps.buildenv1.outputs.symbols_archive }}" - echo ::set-env name=ARTIFACT_PATTERN::HighFidelity-Beta-*.$INSTALLER_EXT + echo ::set-env name=ARTIFACT_PATTERN::Vircadia-Alpha-*.$INSTALLER_EXT # Build type variables if [ "${{ matrix.build_type }}" = "full" ]; then echo ::set-env name=CLIENT_ONLY::FALSE - echo ::set-env name=INSTALLER::HighFidelity-Beta-$RELEASE_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT + echo ::set-env name=INSTALLER::Vircadia-Alpha-$BUILD_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT else echo ::set-env name=CLIENT_ONLY::TRUE - echo ::set-env name=INSTALLER::HighFidelity-Beta-Interface-$RELEASE_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT + echo ::set-env name=INSTALLER::Vircadia-Alpha-Interface-$BUILD_NUMBER-$GIT_COMMIT_SHORT.$INSTALLER_EXT fi - # Linux build variables - if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then - echo ::set-env name=PYTHON_EXEC::python3 - echo ::set-env name=CMAKE_EXTRA::"" - fi - # Mac build variables - if [ "${{ matrix.os }}" = "macOS-latest" ]; then - echo ::set-env name=CMAKE_EXTRA::"-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -G Xcode" - fi - # Windows build variables - if [ "${{ matrix.os }}" = "windows-latest" ]; then - echo ::set-env name=CMAKE_EXTRA::"-A x64" - echo ::set-env name=HF_PFX_PASSPHRASE::${{secrets.pfx_key}} - echo "::set-env name=HF_PFX_FILE::${{runner.workspace}}\build\codesign.pfx" - fi - - name: Clear Working Directory - if: matrix.os == 'windows-latest' + - name: Clear working directory + if: startsWith(matrix.os, 'windows') shell: bash working-directory: ${{runner.workspace}} run: rm -rf ./* @@ -168,89 +102,119 @@ jobs: with: submodules: true fetch-depth: 1 - - name: Create Build Directory - run: cmake -E make_directory ${{runner.workspace}}/build - - name: Decrypt Signing Key (Windows) - if: matrix.os == 'windows-latest' - working-directory: ${{runner.workspace}}/build + - name: Install dependencies + if: startsWith(matrix.os, 'ubuntu') shell: bash - run: gpg --batch --yes -o codesign.pfx --passphrase "${{secrets.gpg_symmetric_key}}" --decrypt $GITHUB_WORKSPACE/tools/ci-scripts/codesign.pfx.gpg - - name: Import Signing Key (Windows) - if: matrix.os == 'windows-latest' - working-directory: ${{runner.workspace}}/build - shell: powershell - run: | - $mypwd=ConvertTo-SecureString -String ${{ secrets.pfx_key }} -Force -AsPlainText - Import-PfxCertificate -Password $mypwd -CertStoreLocation Cert:\CurrentUser\My -FilePath ${{runner.workspace}}\build\codesign.pfx - Import-PfxCertificate -Password $mypwd -CertStoreLocation Cert:\LocalMachine\My -FilePath ${{runner.workspace}}\build\codesign.pfx + run: | + echo "Installing Python Modules:" + pip3 install distro || exit 1 + echo "Updating apt repository index" + sudo apt update || exit 1 + echo "Installing apt packages" + sudo apt install -y ${{ matrix.apt-dependencies }} || exit 1 - name: Install Python modules - if: matrix.os != 'ubuntu-latest' + if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'macOS') shell: bash run: $PYTHON_EXEC -m pip install boto3 PyGithub + - name: Create build environment + shell: bash + run: cmake -E make_directory "${{runner.workspace}}/build" - name: Configure CMake working-directory: ${{runner.workspace}}/build shell: bash - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCLIENT_ONLY:BOOLEAN=$CLIENT_ONLY $CMAKE_EXTRA - - name: Build Application + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DVCPKG_BUILD_TYPE=release -DCLIENT_ONLY:BOOLEAN=$CLIENT_ONLY -DBYPASS_SIGNING:BOOLEAN=TRUE $CMAKE_EXTRA + - name: Build application working-directory: ${{runner.workspace}}/build shell: bash - run: cmake --build . --config $BUILD_TYPE --target $APP_NAME - - name: Build Console + run: cmake --build . --config $BUILD_TYPE --target $APP_NAME $CMAKE_BUILD_EXTRA + - name: Build domain server working-directory: ${{runner.workspace}}/build shell: bash - run: cmake --build . --config $BUILD_TYPE --target packaged-server-console - - name: Build Domain Server (FullBuild) - if: matrix.build_type == 'full' - shell: bash - working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --target domain-server - - name: Build Assignment Client (FullBuild) - if: matrix.build_type == 'full' - shell: bash - working-directory: ${{runner.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --target assignment-client - - name: Build Installer + run: cmake --build . --config $BUILD_TYPE --target domain-server $CMAKE_BUILD_EXTRA + - name: Build assignment client working-directory: ${{runner.workspace}}/build shell: bash - run: cmake --build . --config $BUILD_TYPE --target package - - name: Sign Installer (Windows) - if: matrix.os == 'windows-latest' - shell: powershell - working-directory: C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64 - run: .\signtool.exe sign /fd sha256 /f ${{runner.workspace}}\build\codesign.pfx /p ${{secrets.pfx_key}} /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 ${{runner.workspace}}\build\${env:INSTALLER} - - name: Upload Artifact - if: matrix.os != 'ubuntu-latest' + run: cmake --build . --config $BUILD_TYPE --target assignment-client $CMAKE_BUILD_EXTRA + - name: Build console + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake --build . --config $BUILD_TYPE --target packaged-server-console $CMAKE_BUILD_EXTRA + - name: Build installer + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + echo "Retry code from https://unix.stackexchange.com/a/137639" + function fail { + echo $1 >&2 + exit 1 + } + function retry { + local n=1 + local max=5 + local delay=15 + while true; do + "$@" && break || { + if [[ $n -lt $max ]]; then + ((n++)) + echo "Command failed. Attempt $n/$max:" + sleep $delay; + else + fail "The command has failed after $n attempts." + fi + } + done + } + retry cmake --build . --config $BUILD_TYPE --target package $CMAKE_BUILD_EXTRA + #- name: Sign installer (Windows) + # if: startsWith(matrix.os, 'windows') + # shell: powershell + # working-directory: C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64 + # run: .\signtool.exe sign /fd sha256 /f ${{runner.workspace}}\build\codesign.pfx /p ${{secrets.pfx_key}} /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 ${{runner.workspace}}\build\${env:INSTALLER} + - name: Output system stats + if: ${{ always() }} + working-directory: ${{runner.workspace}}/build + shell: bash + run: | + echo "Disk usage:" + df -h + - name: Output installer logs + if: failure() && startsWith(matrix.os, 'windows') + shell: bash + working-directory: ${{runner.workspace}}/build + run: cat ./_CPack_Packages/win64/NSIS/NSISOutput.log + - name: Upload artifact + if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'macOS') shell: bash working-directory: ${{runner.workspace}}/build env: AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} run: $PYTHON_EXEC $GITHUB_WORKSPACE/tools/ci-scripts/upload.py - - name: Archive Symbols - if: (matrix.os == 'windows-latest') || (matrix.os == 'macOS-latest') - working-directory: ${{runner.workspace}} - shell: bash - run: | - SYMBOLS_TEMP="symbols-temp" - mkdir $SYMBOLS_TEMP - find "./build" \( -path '*/tools/gpu-frame-player/*' -or -path '*/interface/*' -or -path '*/plugins/*' \) -regex ".*\.$SYMBOL_REGEX" -exec cp -r {} $SYMBOLS_TEMP \; - cd $SYMBOLS_TEMP - $ZIP_COMMAND $ZIP_ARGS ../${{ steps.buildenv1.outputs.symbols_archive }} . - - name: Upload Symbols - if: (matrix.os == 'windows-latest') || (matrix.os == 'macOS-latest') - working-directory: ${{runner.workspace}} - shell: bash - run: | - curl --data-binary @${{ steps.buildenv1.outputs.symbols_archive }} "$CMAKE_BACKTRACE_URL/post?format=symbols&token=$CMAKE_BACKTRACE_SYMBOLS_TOKEN&upload_file=${{steps.buildenv1.outputs.symbols_archive}}&tag=$RELEASE_NUMBER" - # - name: Debug List Symbols - # if: (matrix.os == 'windows-latest') || (matrix.os == 'macOS-latest') - # working-directory: ${{runner.workspace}} - # shell: bash - # run: | - # unzip -v "${{runner.workspace}}/${{ steps.buildenv1.outputs.symbols_archive }}" - # - name: Debug Upload Symbols Artifact - # if: (matrix.os == 'windows-latest') || (matrix.os == 'macOS-latest') - # uses: actions/upload-artifact@v1 - # with: - # name: symbols - # path: ${{runner.workspace}}/${{ steps.buildenv1.outputs.symbols_archive }} + #- name: Archive symbols + # if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'macOS') + # working-directory: ${{runner.workspace}} + # shell: bash + # run: | + # SYMBOLS_TEMP="symbols-temp" + # mkdir $SYMBOLS_TEMP + # find "./build" \( -path '*/tools/gpu-frame-player/*' -or -path '*/interface/*' -or -path '*/plugins/*' \) -regex ".*\.$SYMBOL_REGEX" -exec cp -r {} $SYMBOLS_TEMP \; + # cd $SYMBOLS_TEMP + # $ZIP_COMMAND $ZIP_ARGS ../${{ steps.buildenv1.outputs.symbols_archive }} . + #- name: Upload symbols + # if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'macOS') + # working-directory: ${{runner.workspace}} + # shell: bash + # run: | + # curl --data-binary @${{ steps.buildenv1.outputs.symbols_archive }} "$CMAKE_BACKTRACE_URL/post?format=symbols&token=$CMAKE_BACKTRACE_SYMBOLS_TOKEN&upload_file=${{steps.buildenv1.outputs.symbols_archive}}&tag=$BUILD_NUMBER" + #- name: Debug list symbols + # if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'macOS') + # working-directory: ${{runner.workspace}} + # shell: bash + # run: | + # unzip -v "${{runner.workspace}}/${{ steps.buildenv1.outputs.symbols_archive }}" + #- name: Upload debug list symbols + # if: startsWith(matrix.os, 'windows') || startsWith(matrix.os, 'macOS') + # uses: actions/upload-artifact@v1 + # with: + # name: symbols + # path: ${{runner.workspace}}/${{ steps.buildenv1.outputs.symbols_archive }} diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 59e53bb2cb..a8ce7e30e5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -112,11 +112,12 @@ Agent::Agent(ReceivedMessage& message) : packetReceiver.registerListenerForTypes( { PacketType::MixedAudio, PacketType::SilentAudioFrame }, - this, "handleAudioPacket"); + PacketReceiver::makeUnsourcedListenerReference(this, &Agent::handleAudioPacket)); packetReceiver.registerListenerForTypes( { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, - this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); + PacketReceiver::makeSourcedListenerReference(this, &Agent::handleOctreePacket)); + packetReceiver.registerListener(PacketType::SelectedAudioFormat, + PacketReceiver::makeUnsourcedListenerReference(this, &Agent::handleSelectedAudioFormat)); // 100Hz timer for audio const int TARGET_INTERVAL_MSEC = 10; // 10ms diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index ce724d7368..50eee258ab 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -118,8 +118,10 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri setUpStatusToMonitor(); } auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::CreateAssignment, this, "handleCreateAssignmentPacket"); - packetReceiver.registerListener(PacketType::StopNode, this, "handleStopNodePacket"); + packetReceiver.registerListener(PacketType::CreateAssignment, + PacketReceiver::makeUnsourcedListenerReference(this, &AssignmentClient::handleCreateAssignmentPacket)); + packetReceiver.registerListener(PacketType::StopNode, + PacketReceiver::makeUnsourcedListenerReference(this, &AssignmentClient::handleStopNodePacket)); } void AssignmentClient::stopAssignmentClient() { diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 4c7f71a7aa..68c0dfc9fd 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -72,7 +72,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen auto nodeList = DependencyManager::set(listenPort); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket"); + packetReceiver.registerListener(PacketType::AssignmentClientStatus, + PacketReceiver::makeUnsourcedListenerReference(this, &AssignmentClientMonitor::handleChildStatusPacket)); adjustOSResources(std::max(_numAssignmentClientForks, _maxAssignmentClientForks)); // use QProcess to fork off a process for each of the child assignment clients diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index b3344e3832..ffb6747fd7 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -308,7 +308,8 @@ AssetServer::AssetServer(ReceivedMessage& message) : // Queue all requests until the Asset Server is fully setup auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListenerForTypes({ PacketType::AssetGet, PacketType::AssetGetInfo, PacketType::AssetUpload, PacketType::AssetMappingOperation }, this, "queueRequests"); + packetReceiver.registerListenerForTypes({ PacketType::AssetGet, PacketType::AssetGetInfo, PacketType::AssetUpload, PacketType::AssetMappingOperation }, + PacketReceiver::makeSourcedListenerReference(this, &AssetServer::queueRequests)); #ifdef Q_OS_WIN updateConsumedCores(); @@ -464,10 +465,14 @@ void AssetServer::completeSetup() { qCDebug(asset_server) << "Overriding temporary queuing packet handler."; // We're fully setup, override the request queueing handler and replay all requests auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); - packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); - packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); - packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation"); + packetReceiver.registerListener(PacketType::AssetGet, + PacketReceiver::makeSourcedListenerReference(this, &AssetServer::handleAssetGet)); + packetReceiver.registerListener(PacketType::AssetGetInfo, + PacketReceiver::makeSourcedListenerReference(this, &AssetServer::handleAssetGetInfo)); + packetReceiver.registerListener(PacketType::AssetUpload, + PacketReceiver::makeSourcedListenerReference(this, &AssetServer::handleAssetUpload)); + packetReceiver.registerListener(PacketType::AssetMappingOperation, + PacketReceiver::makeSourcedListenerReference(this, &AssetServer::handleAssetMappingOperation)); replayRequests(); } diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 161a6f4285..42a269c544 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -101,20 +101,23 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::InjectorGainSet, PacketType::AudioSoloRequest, PacketType::StopInjector }, - this, "queueAudioPacket"); + PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::queueAudioPacket) + ); // packets whose consequences are global should be processed on the main thread - packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket"); - packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); - packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); + packetReceiver.registerListener(PacketType::MuteEnvironment, + PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::handleMuteEnvironmentPacket)); + packetReceiver.registerListener(PacketType::NodeMuteRequest, + PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::handleNodeMuteRequestPacket)); + packetReceiver.registerListener(PacketType::KillAvatar, + PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::handleKillAvatarPacket)); packetReceiver.registerListenerForTypes({ PacketType::ReplicatedMicrophoneAudioNoEcho, PacketType::ReplicatedMicrophoneAudioWithEcho, PacketType::ReplicatedInjectAudio, - PacketType::ReplicatedSilentAudioFrame - }, - this, "queueReplicatedAudioPacket" + PacketType::ReplicatedSilentAudioFrame }, + PacketReceiver::makeUnsourcedListenerReference(this, &AudioMixer::queueReplicatedAudioPacket) ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 807f54953e..27b7d0d302 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -71,26 +71,38 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &AvatarMixer::handleAvatarKilled); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AvatarData, this, "queueIncomingPacket"); - packetReceiver.registerListener(PacketType::AdjustAvatarSorting, this, "handleAdjustAvatarSorting"); - packetReceiver.registerListener(PacketType::AvatarQuery, this, "handleAvatarQueryPacket"); - packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket"); - packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); - packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket"); - packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); - packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); - packetReceiver.registerListener(PacketType::SetAvatarTraits, this, "queueIncomingPacket"); - packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, this, "queueIncomingPacket"); + packetReceiver.registerListener(PacketType::AvatarData, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::queueIncomingPacket)); + packetReceiver.registerListener(PacketType::AdjustAvatarSorting, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleAdjustAvatarSorting)); + packetReceiver.registerListener(PacketType::AvatarQuery, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleAvatarQueryPacket)); + packetReceiver.registerListener(PacketType::AvatarIdentity, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleAvatarIdentityPacket)); + packetReceiver.registerListener(PacketType::KillAvatar, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleKillAvatarPacket)); + packetReceiver.registerListener(PacketType::NodeIgnoreRequest, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleNodeIgnoreRequestPacket)); + packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleRadiusIgnoreRequestPacket)); + packetReceiver.registerListener(PacketType::RequestsDomainListData, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleRequestsDomainListDataPacket)); + packetReceiver.registerListener(PacketType::SetAvatarTraits, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::queueIncomingPacket)); + packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::queueIncomingPacket)); packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, - this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::ChallengeOwnership, this, "queueIncomingPacket"); + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::handleOctreePacket)); + packetReceiver.registerListener(PacketType::ChallengeOwnership, + PacketReceiver::makeSourcedListenerReference(this, &AvatarMixer::queueIncomingPacket)); packetReceiver.registerListenerForTypes({ PacketType::ReplicatedAvatarIdentity, PacketType::ReplicatedKillAvatar - }, this, "handleReplicatedPacket"); + }, PacketReceiver::makeUnsourcedListenerReference(this, &AvatarMixer::handleReplicatedPacket)); - packetReceiver.registerListener(PacketType::ReplicatedBulkAvatarData, this, "handleReplicatedBulkAvatarPacket"); + packetReceiver.registerListener(PacketType::ReplicatedBulkAvatarData, + PacketReceiver::makeUnsourcedListenerReference(this, &AvatarMixer::handleReplicatedBulkAvatarPacket)); auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 4c4fcbf2dd..e68f95bda0 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -59,8 +59,7 @@ EntityServer::EntityServer(ReceivedMessage& message) : PacketType::ChallengeOwnership, PacketType::ChallengeOwnershipRequest, PacketType::ChallengeOwnershipReply }, - this, - "handleEntityPacket"); + PacketReceiver::makeSourcedListenerReference(this, &EntityServer::handleEntityPacket)); connect(&_dynamicDomainVerificationTimer, &QTimer::timeout, this, &EntityServer::startDynamicDomainVerification); _dynamicDomainVerificationTimer.setSingleShot(true); diff --git a/assignment-client/src/messages/MessagesMixer.cpp b/assignment-client/src/messages/MessagesMixer.cpp index d2127835f9..bcf4881fcf 100644 --- a/assignment-client/src/messages/MessagesMixer.cpp +++ b/assignment-client/src/messages/MessagesMixer.cpp @@ -25,9 +25,12 @@ MessagesMixer::MessagesMixer(ReceivedMessage& message) : ThreadedAssignment(mess { connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &MessagesMixer::nodeKilled); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::MessagesData, this, "handleMessages"); - packetReceiver.registerListener(PacketType::MessagesSubscribe, this, "handleMessagesSubscribe"); - packetReceiver.registerListener(PacketType::MessagesUnsubscribe, this, "handleMessagesUnsubscribe"); + packetReceiver.registerListener(PacketType::MessagesData, + PacketReceiver::makeSourcedListenerReference(this, &MessagesMixer::handleMessages)); + packetReceiver.registerListener(PacketType::MessagesSubscribe, + PacketReceiver::makeSourcedListenerReference(this, &MessagesMixer::handleMessagesSubscribe)); + packetReceiver.registerListener(PacketType::MessagesUnsubscribe, + PacketReceiver::makeSourcedListenerReference(this, &MessagesMixer::handleMessagesUnsubscribe)); } void MessagesMixer::nodeKilled(SharedNodePointer killedNode) { diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 63520262cd..f72ab0ac05 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1122,8 +1122,10 @@ void OctreeServer::run() { void OctreeServer::domainSettingsRequestComplete() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - packetReceiver.registerListener(PacketType::OctreeDataNack, this, "handleOctreeDataNackPacket"); - packetReceiver.registerListener(getMyQueryMessageType(), this, "handleOctreeQueryPacket"); + packetReceiver.registerListener(PacketType::OctreeDataNack, + PacketReceiver::makeSourcedListenerReference(this, &OctreeServer::handleOctreeDataNackPacket)); + packetReceiver.registerListener(getMyQueryMessageType(), + PacketReceiver::makeSourcedListenerReference(this, &OctreeServer::handleOctreeQueryPacket)); qDebug(octree_server) << "Received domain settings"; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 7c3d491470..065ab12abc 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -83,13 +83,18 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, - this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); + PacketReceiver::makeSourcedListenerReference(this, &EntityScriptServer::handleOctreePacket)); + packetReceiver.registerListener(PacketType::SelectedAudioFormat, + PacketReceiver::makeUnsourcedListenerReference(this, &EntityScriptServer::handleSelectedAudioFormat)); - packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket"); - packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket"); - packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); - packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket"); + packetReceiver.registerListener(PacketType::ReloadEntityServerScript, + PacketReceiver::makeSourcedListenerReference(this, &EntityScriptServer::handleReloadEntityServerScriptPacket)); + packetReceiver.registerListener(PacketType::EntityScriptGetStatus, + PacketReceiver::makeSourcedListenerReference(this, &EntityScriptServer::handleEntityScriptGetStatusPacket)); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, + PacketReceiver::makeSourcedListenerReference(this, &EntityScriptServer::handleEntityServerScriptLogPacket)); + packetReceiver.registerListener(PacketType::EntityScriptCallMethod, + PacketReceiver::makeSourcedListenerReference(this, &EntityScriptServer::handleEntityScriptCallMethodPacket)); static const int LOG_INTERVAL = MSECS_PER_SECOND / 10; auto timer = new QTimer(this); diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 91f5519a33..4c44ed1fbd 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -202,9 +202,9 @@ ; The Inner invocation has written an uninstaller binary for us. ; We need to sign it if it's a production or PR build. !if @PRODUCTION_BUILD@ == 1 - !if @BYPASS_SIGNING@ == 1 + !if @BYPASS_SIGNING@ == TRUE !warning "BYPASS_SIGNING set - installer will not be signed" - !else + !else !system '"@SIGNTOOL_EXECUTABLE@" sign /fd sha256 /f %HF_PFX_FILE% /p %HF_PFX_PASSPHRASE% /tr http://timestamp.comodoca.com?td=sha256 /td SHA256 $%TEMP%\@UNINSTALLER_NAME@' = 0 !endif !endif diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index 5469125162..bffd512890 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -500,6 +500,31 @@ function prepareAccessTokenPrompt(callback) { }); } +function createDomainIDPrompt(callback) { + swal({ + title: 'Finish Registering Domain', + type: 'input', + text: 'Enter a label for this machine.

This will help you identify which domain ID belongs to which machine.

This is a required step for registration.

', + showCancelButton: true, + confirmButtonText: "Create", + closeOnConfirm: false, + html: true + }, function (inputValue) { + if (inputValue === false) { + return false; + } + + if (inputValue === "") { + swal.showInputError("Please enter a valid label for your machine."); + return false; + } + + if (callback) { + callback(inputValue); + } + }); +} + function getMetaverseUrl(callback) { $.ajax('/api/metaverse_info', { success: function(data) { diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 8a9971d520..ea38a30f49 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -40,6 +40,8 @@ $(document).ready(function(){ // call our method to setup the place names table setupPlacesTable(); + // hide the places table for now because we do not want that interacted with from the domain-server + $('#' + Settings.PLACES_TABLE_ID).hide(); setupDomainNetworkingSettings(); // setupDomainLabelSetting(); @@ -363,7 +365,7 @@ $(document).ready(function(){ confirmButtonText: "Create", closeOnConfirm: false, html: true - }, function(inputValue){ + }, function (inputValue) { if (inputValue === false) { swal.close(); @@ -373,7 +375,7 @@ $(document).ready(function(){ } } else { // we're going to change the alert to a new one with a spinner while we create this domain - showSpinnerAlert('Creating domain ID'); + // showSpinnerAlert('Creating domain ID'); createNewDomainID(inputValue, justConnected); } }); @@ -385,7 +387,12 @@ $(document).ready(function(){ "label": label } - $.post("/api/domains", domainJSON, function(data){ + $.post("/api/domains", domainJSON, function(data) { + if (data.status === "failure") { + failedToCreateDomainID(data, justConnected); + return; + } + // we successfully created a domain ID, set it on that field var domainID = data.domain.domainId; console.log("Setting domain id to ", data, domainID); @@ -406,40 +413,50 @@ $(document).ready(function(){ text: successText, html: true, confirmButtonText: 'Save' - }, function(){ + }, function () { saveSettings(); }); - }, 'json').fail(function(){ + }, 'json').fail(function (data) { + failedToCreateDomainID(data, justConnected); + }); + } + + function failedToCreateDomainID(data, justConnected) { + var errorText = "There was a problem creating your new domain ID. Do you want to try again or"; - var errorText = "There was a problem creating your new domain ID. Do you want to try again or"; + if (data && data.status === "failure") { + errorText = "Error: " + data.error + "
Do you want to try again or"; + console.log("Error: " + data.error); + } else { + console.log("Error: Failed to post to metaverse."); + } - if (justConnected) { - errorText += " just save your new access token?

You can always create a new domain ID later."; + if (justConnected) { + errorText += " just save your new access token?

You can always create a new domain ID later."; + } else { + errorText += " cancel?" + } + + // we failed to create the new domain ID, show a sweet-alert that lets them try again or cancel + swal({ + title: '', + type: 'error', + text: errorText, + html: true, + confirmButtonText: 'Try again', + showCancelButton: true, + closeOnConfirm: false + }, function (isConfirm) { + if (isConfirm) { + // they want to try creating a domain ID again + showDomainCreationAlert(justConnected); } else { - errorText += " cancel?" - } - - // we failed to create the new domain ID, show a sweet-alert that lets them try again or cancel - swal({ - title: '', - type: 'error', - text: errorText, - html: true, - confirmButtonText: 'Try again', - showCancelButton: true, - closeOnConfirm: false - }, function(isConfirm){ - if (isConfirm) { - // they want to try creating a domain ID again - showDomainCreationAlert(justConnected); - } else { - // they want to cancel - if (justConnected) { - // since they just connected we need to save the access token here - saveSettings(); - } + // they want to cancel + if (justConnected) { + // since they just connected we need to save the access token here + saveSettings(); } - }); + } }); } @@ -711,8 +728,8 @@ $(document).ready(function(){ name: 'places', label: 'Places', html_id: Settings.PLACES_TABLE_ID, - help: "The following places currently point to this domain.
To point places to this domain, " - + " go to the My Places " + help: "To point places to this domain, " + + " go to the Places " + "page in your Metaverse account.", read_only: true, can_add_new_rows: false, @@ -745,9 +762,10 @@ $(document).ready(function(){ var errorEl = createDomainLoadingError("There was an error retrieving your places."); $("#" + Settings.PLACES_TABLE_ID).after(errorEl); - var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name'); - temporaryPlaceButton.hide(); - $('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton); + // DISABLE TEMP PLACE NAME BUTTON... + // var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name'); + // temporaryPlaceButton.hide(); + // $('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton); if (accessTokenIsSet()) { appendAddButtonToPlacesTable(); } diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index 4093eda39a..6d56a99682 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -19,7 +19,7 @@ -
@@ -102,5 +91,142 @@
+
+ + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ diff --git a/scripts/system/create/entityList/html/js/entityList.js b/scripts/system/create/entityList/html/js/entityList.js index aa40d5286f..be79593511 100644 --- a/scripts/system/create/entityList/html/js/entityList.js +++ b/scripts/system/create/entityList/html/js/entityList.js @@ -47,6 +47,14 @@ const COLUMNS = { alwaysShown: true, defaultSortOrder: ASCENDING_SORT, }, + parentState: { + columnHeader: "A", + vglyph: true, + dropdownLabel: "Hierarchy", + propertyID: "parentState", + initialWidth: 0.08, + defaultSortOrder: DESCENDING_SORT, + }, name: { columnHeader: "Name", propertyID: "name", @@ -134,6 +142,20 @@ const COLUMNS = { initialWidth: 0.06, defaultSortOrder: DESCENDING_SORT, }, + created: { + columnHeader: "Created (UTC)", + dropdownLabel: "Creation Date", + propertyID: "created", + initialWidth: 0.38, + defaultSortOrder: DESCENDING_SORT, + }, + lastEdited: { + columnHeader: "Modified (UTC)", + dropdownLabel: "Modification Date", + propertyID: "lastEdited", + initialWidth: 0.38, + defaultSortOrder: DESCENDING_SORT, + }, }; const FILTER_TYPES = [ @@ -200,7 +222,10 @@ let elEntityTable, elRefresh, elToggleLocked, elToggleVisible, - elHmdMultiSelect, + elActionsMenu, + elSelectionMenu, + elMenuBackgroundOverlay, + elHmdMultiSelect, elHmdCopy, elHmdCut, elHmdPaste, @@ -210,6 +235,18 @@ let elEntityTable, elParent, elUnparent, elDelete, + elMoveEntitySelectionToAvatar, + elSelectAll, + elSelectInverse, + elSelectNone, + elSelectAllInBox, + elSelectAllTouchingBox, + elSelectParent, + elSelectTopParent, + elAddChildrenToSelection, + elSelectFamily, + elSelectTopFamily, + elTeleportToEntity, elFilterTypeMultiselectBox, elFilterTypeText, elFilterTypeOptions, @@ -252,8 +289,11 @@ function loaded() { elEntityTableScroll = document.getElementById("entity-table-scroll"); elRefresh = document.getElementById("refresh"); elToggleLocked = document.getElementById("locked"); - elToggleVisible = document.getElementById("visible"); + elToggleVisible = document.getElementById("visible"); elHmdMultiSelect = document.getElementById("hmdmultiselect"); + elActionsMenu = document.getElementById("actions"); + elSelectionMenu = document.getElementById("selection"); + elMenuBackgroundOverlay = document.getElementById("menuBackgroundOverlay"); elHmdCopy = document.getElementById("hmdcopy"); elHmdCut = document.getElementById("hmdcut"); elHmdPaste = document.getElementById("hmdpaste"); @@ -263,6 +303,18 @@ function loaded() { elParent = document.getElementById("parent"); elUnparent = document.getElementById("unparent"); elDelete = document.getElementById("delete"); + elMoveEntitySelectionToAvatar = document.getElementById("moveEntitySelectionToAvatar"); + elSelectAll = document.getElementById("selectall"); + elSelectInverse = document.getElementById("selectinverse"); + elSelectNone = document.getElementById("selectnone"); + elSelectAllInBox = document.getElementById("selectallinbox"); + elSelectAllTouchingBox = document.getElementById("selectalltouchingbox"); + elSelectParent = document.getElementById("selectparent"); + elSelectTopParent = document.getElementById("selecttopparent"); + elAddChildrenToSelection = document.getElementById("addchildrentoselection"); + elSelectFamily = document.getElementById("selectfamily"); + elSelectTopFamily = document.getElementById("selecttopfamily"); + elTeleportToEntity = document.getElementById("teleport-to-entity"); elFilterTypeMultiselectBox = document.getElementById("filter-type-multiselect-box"); elFilterTypeText = document.getElementById("filter-type-text"); elFilterTypeOptions = document.getElementById("filter-type-options"); @@ -300,32 +352,146 @@ function loaded() { } EventBridge.emitWebEvent(JSON.stringify({ type: 'hmdMultiSelectMode', value: hmdMultiSelectMode })); }; + elActionsMenu.onclick = function() { + document.getElementById("menuBackgroundOverlay").style.display = "block"; + document.getElementById("actions-menu").style.display = "block"; + }; + elSelectionMenu.onclick = function() { + document.getElementById("menuBackgroundOverlay").style.display = "block"; + document.getElementById("selection-menu").style.display = "block"; + }; + elMenuBackgroundOverlay.onclick = function() { + closeAllEntityListMenu(); + }; elHmdCopy.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'copy' })); + closeAllEntityListMenu(); }; elHmdCut.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'cut' })); + closeAllEntityListMenu(); }; elHmdPaste.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'paste' })); + closeAllEntityListMenu(); }; elHmdDuplicate.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'duplicate' })); - }; + closeAllEntityListMenu(); + }; elParent.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'parent' })); + closeAllEntityListMenu(); }; elUnparent.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'unparent' })); + closeAllEntityListMenu(); }; elUndo.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'undo' })); + closeAllEntityListMenu(); }; elRedo.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'redo' })); + closeAllEntityListMenu(); }; elDelete.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' })); + closeAllEntityListMenu(); + }; + elMoveEntitySelectionToAvatar.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'moveEntitySelectionToAvatar' })); + closeAllEntityListMenu(); + }; + elSelectAll.onclick = function() { + + let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); + let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { + return selectedEntities.includes(visibleEntityID); + }); + + let selection = []; + + if (!selectionIncludesAllVisibleEntityIDs) { + selection = visibleEntityIDs; + } + + updateSelectedEntities(selection, false); + + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": selection + })); + + closeAllEntityListMenu(); + }; + elSelectInverse.onclick = function() { + let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); + let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { + return selectedEntities.includes(visibleEntityID); + }); + + let selection = []; + + if (!selectionIncludesAllVisibleEntityIDs) { + visibleEntityIDs.forEach(function(id) { + if (!selectedEntities.includes(id)) { + selection.push(id); + } + }); + } + + updateSelectedEntities(selection, false); + + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": selection + })); + + closeAllEntityListMenu(); + }; + elSelectNone.onclick = function() { + updateSelectedEntities([], false); + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": [] + })); + closeAllEntityListMenu(); + }; + elSelectAllInBox.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectAllInBox' })); + closeAllEntityListMenu(); + }; + elSelectAllTouchingBox.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectAllTouchingBox' })); + closeAllEntityListMenu(); + }; + elSelectParent.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectParent' })); + closeAllEntityListMenu(); + }; + elSelectTopParent.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectTopParent' })); + closeAllEntityListMenu(); + }; + elAddChildrenToSelection.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'addChildrenToSelection' })); + closeAllEntityListMenu(); + }; + elSelectFamily.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectFamily' })); + closeAllEntityListMenu(); + }; + elSelectTopFamily.onclick = function() { + EventBridge.emitWebEvent(JSON.stringify({ type: 'selectTopFamily' })); + closeAllEntityListMenu(); + }; + elTeleportToEntity.onclick = function () { + EventBridge.emitWebEvent(JSON.stringify({ type: "teleportToEntity" })); + closeAllEntityListMenu(); }; elToggleSpaceMode.onclick = function() { EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleSpaceMode' })); @@ -384,9 +550,12 @@ function loaded() { elTh.setAttribute("id", thID); elTh.setAttribute("columnIndex", columnIndex); elTh.setAttribute("columnID", columnID); - if (columnData.glyph) { + if (columnData.glyph || columnData.vglyph) { let elGlyph = document.createElement("span"); elGlyph.className = "glyph"; + if (columnData.vglyph) { + elGlyph.className = "vglyph"; + } elGlyph.innerHTML = columnData.columnHeader; elTh.appendChild(elGlyph); } else { @@ -686,10 +855,13 @@ function loaded() { isBaked: entity.isBaked, drawCalls: displayIfNonZero(entity.drawCalls), hasScript: entity.hasScript, + parentState: entity.parentState, + created: entity.created, + lastEdited: entity.lastEdited, elRow: null, // if this entity has a visible row element assigned to it selected: false // if this entity is selected for edit regardless of having a visible row }; - + entities.push(entityData); entitiesByID[entityData.id] = entityData; }); @@ -871,7 +1043,7 @@ function loaded() { function updateSelectedEntities(selectedIDs, autoScroll) { let notFound = false; - + // reset all currently selected entities and their rows first selectedEntities.forEach(function(id) { let entity = entitiesByID[id]; @@ -882,7 +1054,7 @@ function loaded() { } } }); - + // then reset selected entities list with newly selected entities and set them selected selectedEntities = []; selectedIDs.forEach(function(id) { @@ -945,6 +1117,8 @@ function loaded() { let elCell = elRow.childNodes[i]; if (column.data.glyph) { elCell.innerHTML = itemData[column.data.propertyID] ? column.data.columnHeader : null; + } else if (column.data.vglyph) { + elCell.innerHTML = itemData[column.data.propertyID]; } else { let value = itemData[column.data.propertyID]; if (column.data.format) { @@ -1032,6 +1206,9 @@ function loaded() { let column = columnsByID[columnID]; let visible = column.elTh.style.visibility !== "hidden"; let className = column.data.glyph ? "glyph" : ""; + if (column.data.vglyph) { + className = "vglyph"; + } className += visible ? "" : " hidden"; return className; } @@ -1381,7 +1558,7 @@ function loaded() { break; } - if (controlKey && keyCodeString === "A") { + if (controlKey && !shiftKey && !altKey && keyCodeString === "A") { let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { return selectedEntities.includes(visibleEntityID); @@ -1404,6 +1581,32 @@ function loaded() { return; } + if (controlKey && !shiftKey && !altKey && keyCodeString === "I") { + let visibleEntityIDs = visibleEntities.map(visibleEntity => visibleEntity.id); + let selectionIncludesAllVisibleEntityIDs = visibleEntityIDs.every(visibleEntityID => { + return selectedEntities.includes(visibleEntityID); + }); + + let selection = []; + + if (!selectionIncludesAllVisibleEntityIDs) { + visibleEntityIDs.forEach(function(id) { + if (!selectedEntities.includes(id)) { + selection.push(id); + } + }); + } + + updateSelectedEntities(selection); + + EventBridge.emitWebEvent(JSON.stringify({ + "type": "selectionUpdate", + "focus": false, + "entityIds": selection + })); + + return; + } EventBridge.emitWebEvent(JSON.stringify({ type: 'keyUpEvent', @@ -1454,16 +1657,8 @@ function loaded() { } else if (data.type === "confirmHMDstate") { if (data.isHmd) { document.getElementById("hmdmultiselect").style.display = "inline"; - document.getElementById("hmdcopy").style.display = "inline"; - document.getElementById("hmdcut").style.display = "inline"; - document.getElementById("hmdpaste").style.display = "inline"; - document.getElementById("hmdduplicate").style.display = "inline"; } else { - document.getElementById("hmdmultiselect").style.display = "none"; - document.getElementById("hmdcopy").style.display = "none"; - document.getElementById("hmdcut").style.display = "none"; - document.getElementById("hmdpaste").style.display = "none"; - document.getElementById("hmdduplicate").style.display = "none"; + document.getElementById("hmdmultiselect").style.display = "none"; } } }); @@ -1489,4 +1684,11 @@ function loaded() { $(window).blur(function() { entityListContextMenu.close(); }); + + function closeAllEntityListMenu() { + document.getElementById("menuBackgroundOverlay").style.display = "none"; + document.getElementById("selection-menu").style.display = "none"; + document.getElementById("actions-menu").style.display = "none"; + } + } diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index 8364d5b155..f3f92a887e 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -1618,7 +1618,8 @@ const GROUPS = [ type: "vec3", vec3Type: "pyr", multiplier: DEGREES_TO_RADIANS, - decimals: 4, + decimals: 6, + step: 1, subLabels: [ "x", "y", "z" ], unit: "deg/s", propertyID: "localAngularVelocity", diff --git a/scripts/system/create/entitySelectionTool/entitySelectionTool.js b/scripts/system/create/entitySelectionTool/entitySelectionTool.js index 0250ead0a9..ffa828affe 100644 --- a/scripts/system/create/entitySelectionTool/entitySelectionTool.js +++ b/scripts/system/create/entitySelectionTool/entitySelectionTool.js @@ -19,6 +19,7 @@ const SPACE_LOCAL = "local"; const SPACE_WORLD = "world"; const HIGHLIGHT_LIST_NAME = "editHandleHighlightList"; +const MIN_DISTANCE_TO_REZ_FROM_AVATAR = 3; Script.include([ "../../libraries/controllers.js", @@ -26,7 +27,6 @@ Script.include([ "../../libraries/utils.js" ]); - function deepCopy(v) { return JSON.parse(JSON.stringify(v)); } @@ -636,6 +636,141 @@ SelectionManager = (function() { } }; + that.teleportToEntity = function() { + if (that.hasSelection()) { + var distanceFromTarget = MIN_DISTANCE_TO_REZ_FROM_AVATAR + Math.max(Math.max(that.worldDimensions.x, that.worldDimensions.y), that.worldDimensions.z); + var teleportTargetPosition = Vec3.sum(that.worldPosition, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: distanceFromTarget })); + MyAvatar.goToLocation(teleportTargetPosition, false); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + that.moveEntitiesSelectionToAvatar = function() { + if (that.hasSelection() && that.hasUnlockedSelection()) { + that.saveProperties(); + var distanceFromTarget = MIN_DISTANCE_TO_REZ_FROM_AVATAR + Math.max(Math.max(that.worldDimensions.x, that.worldDimensions.y), that.worldDimensions.z); + var targetPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -distanceFromTarget })); + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in that.selections + var toMove = that.selections.filter(function (selection) { + if (that.selections.indexOf(that.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + for (var i = 0; i < toMove.length; i++) { + var id = toMove[i]; + var properties = that.savedProperties[id]; + var relativePosition = Vec3.subtract(properties.position, that.worldPosition); + var newPosition = Vec3.sum(relativePosition, targetPosition); + Entities.editEntity(id, { "position": newPosition }); + } + that._update(false, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected or the selection has locked entities."); + } + }; + + that.selectParent = function() { + if (that.hasSelection()) { + var currentSelection = that.selections; + that.selections = []; + for (var i = 0; i < currentSelection.length; i++) { + var properties = Entities.getEntityProperties(currentSelection[i], ['parentID']); + if (properties.parentID !== Uuid.NULL) { + that.selections.push(properties.parentID); + } + } + that._update(true, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + that.selectTopParent = function() { + if (that.hasSelection()) { + var currentSelection = that.selections; + that.selections = []; + for (var i = 0; i < currentSelection.length; i++) { + var topParentId = getTopParent(currentSelection[i]); + if (topParentId !== Uuid.NULL) { + that.selections.push(topParentId); + } + } + that._update(true, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + function getTopParent(id) { + var topParentId = Uuid.NULL; + var properties = Entities.getEntityProperties(id, ['parentID']); + if (properties.parentID === Uuid.NULL) { + topParentId = id; + } else { + topParentId = getTopParent(properties.parentID); + } + return topParentId; + } + + that.addChildrenToSelection = function() { + if (that.hasSelection()) { + for (var i = 0; i < that.selections.length; i++) { + var childrenIDs = Entities.getChildrenIDs(that.selections[i]); + var collectNewChildren; + var j; + var k = 0; + do { + collectNewChildren = Entities.getChildrenIDs(childrenIDs[k]); + if (collectNewChildren.length > 0) { + for (j = 0; j < collectNewChildren.length; j++) { + childrenIDs.push(collectNewChildren[j]); + } + } + k++; + } while (k < childrenIDs.length); + if (childrenIDs.length > 0) { + for (j = 0; j < childrenIDs.length; j++) { + that.selections.push(childrenIDs[j]); + } + } + } + that._update(true, this); + } else { + audioFeedback.rejection(); + Window.notifyEditError("You have nothing selected."); + } + }; + + that.hasUnlockedSelection = function() { + var selectionNotLocked = true; + for (var i = 0; i < that.selections.length; i++) { + var properties = Entities.getEntityProperties(that.selections[i], ['locked']); + if (properties.locked) { + selectionNotLocked = false; + break; + } + } + return selectionNotLocked; + }; + + that.selectFamily = function() { + that.selectParent(); + that.addChildrenToSelection(); + }; + + that.selectTopFamily = function() { + that.selectTopParent(); + that.addChildrenToSelection(); + }; + return that; })(); @@ -660,8 +795,10 @@ SelectionDisplay = (function() { const COLOR_HOVER = { red: 255, green: 220, blue: 82 }; const COLOR_DUPLICATOR = { red: 162, green: 0, blue: 255 }; const COLOR_ROTATE_CURRENT_RING = { red: 255, green: 99, blue: 9 }; - const COLOR_BOUNDING_EDGE = { red: 128, green: 128, blue: 128 }; - const COLOR_SCALE_CUBE = { red: 160, green: 160, blue: 160 }; + const COLOR_BOUNDING_EDGE = { red: 160, green: 160, blue: 160 }; + const COLOR_BOUNDING_EDGE_PARENT = { red: 194, green: 123, blue: 0 }; + const COLOR_BOUNDING_EDGE_CHILDREN = { red: 0, green: 168, blue: 214 }; + const COLOR_SCALE_CUBE = { red: 192, green: 192, blue: 192 }; const COLOR_DEBUG_PICK_PLANE = { red: 255, green: 255, blue: 255 }; const COLOR_DEBUG_PICK_PLANE_HIT = { red: 255, green: 165, blue: 0 }; @@ -1791,6 +1928,18 @@ SelectionDisplay = (function() { var rotationZ = Quat.multiply(rotation, localRotationZ); worldRotationZ = rotationZ; + var handleBoundingBoxColor = COLOR_BOUNDING_EDGE; + if (SelectionManager.selections.length === 1) { + var parentState = getParentState(SelectionManager.selections[0]); + if (parentState === "CHILDREN") { + handleBoundingBoxColor = COLOR_BOUNDING_EDGE_CHILDREN; + } else { + if (parentState === "PARENT" || parentState === "PARENT_CHILDREN") { + handleBoundingBoxColor = COLOR_BOUNDING_EDGE_PARENT; + } + } + } + var selectionBoxGeometry = { position: position, rotation: rotation, @@ -1912,6 +2061,7 @@ SelectionDisplay = (function() { Entities.editEntity(handleBoundingBox, { position: position, rotation: rotation, + color: handleBoundingBoxColor, dimensions: dimensions }); diff --git a/scripts/system/create/qml/NewMaterialDialog.qml b/scripts/system/create/qml/NewMaterialDialog.qml index 3cc619e176..e08ca868b6 100644 --- a/scripts/system/create/qml/NewMaterialDialog.qml +++ b/scripts/system/create/qml/NewMaterialDialog.qml @@ -55,7 +55,7 @@ Rectangle { Text { id: text1 - text: qsTr("Material URL (Optional)") + text: qsTr("Material URL (Optional)") color: "#ffffff" font.pixelSize: 12 } diff --git a/scripts/system/create/qml/NewModelDialog.qml b/scripts/system/create/qml/NewModelDialog.qml index dd4ef3c8ad..758706a79b 100644 --- a/scripts/system/create/qml/NewModelDialog.qml +++ b/scripts/system/create/qml/NewModelDialog.qml @@ -55,7 +55,7 @@ Rectangle { Text { id: text1 - text: qsTr("Model URL") + text: qsTr("Model URL (.fbx, .fst, .glb, .gltf, .obj, .gz)") color: "#ffffff" font.pixelSize: 12 } diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 8a381ff4ad..1f1fb9c86a 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -415,6 +415,13 @@ input[type=button].glyph, button.hifi-edit-button.glyph { padding: 0; } +input[type=button].normal, button.hifi-edit-button.normal { + font-family: FiraSans-SemiBold; + font-size: 15px; + text-transform: none; + padding: 0; +} + input[type=button].vglyph, button.hifi-edit-button.vglyph { font-family: Vircadia-Glyphs; font-size: 20px; @@ -1236,7 +1243,6 @@ textarea:enabled[scrolling="true"]::-webkit-resizer { background: #2e2e2e url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACKSURBVChTjdAxDsMgDAXQT4UYuQIzCwsSKxsSJ4YDoByDY7AwUOG2aZMQqX+xhd9gzIwxA3/k8a7LCCFgraX+Fk4UY4RSCoyxNfwgzjlyzhhjXOEvSimhtUbvB3hGUkp472m2wxUKIaD3TnOCd6jWim3bvlBrfdjJOUeolEJoZj/4PMH83bl/BXgCWSs2Z09IjgoAAAAASUVORK5CYII=) no-repeat bottom right; } - div#grid-section, body#entity-list-body { padding-bottom: 0; margin: 16px; @@ -1267,12 +1273,6 @@ div#grid-section, body#entity-list-body { border-bottom-left-radius: 0; } -#delete { - float: right; - margin-right: 0; - background-color: #ff0000; -} - #entity-list { position: relative; /* New positioning context. */ } @@ -1448,6 +1448,11 @@ input[type=button]#export { font-size: 15px; } +#entity-table-scroll .vglyph { + font-family: Vircadia-Glyphs; + font-size: 15px; +} + #entity-table { margin-top: -28px; margin-bottom: -18px; @@ -1460,7 +1465,7 @@ input[type=button]#export { background: none; } -#entity-table .glyph { +#entity-table .glyph .vglyph { margin: 0 -2px 0 -2px; vertical-align: middle; } @@ -1493,11 +1498,11 @@ input[type=button]#export { outline: none; } -#entity-table th .glyph { +#entity-table th .glyph .vglyph { position: relative; left: 4px; } -#entity-table th .glyph + .sort-order { +#entity-table th .glyph .vglyph + .sort-order { position: relative; left: 4px; } @@ -1524,7 +1529,7 @@ input[type=button]#export { #entity-table td { box-sizing: border-box; } -#entity-table td.glyph { +#entity-table td .glyph .vglyph { text-align: center; padding: 0; } @@ -1860,3 +1865,71 @@ div.multiZoneSelToolbar { padding: 0px; } +#menuBackgroundOverlay{ + background-color:transparent; + position:fixed; + width: 100%; + height: 100%; + top:0; + left:0; + right:0; + bottom:0; + display:none; +} + +div.entity-list-menu { + position: fixed; + display: none; + width: 70%; + height: 30px; + top: 42px; + left: 150px; + right: 0; + bottom: 0; + border-style: solid; + border-color: #505050; + border-width: 1px; + background-color: #c0c0c0; + z-index: 2; + cursor: pointer; +} + +div.menu-separator{ + width: 90%; + height: 2px; + background-color: #505050; + } + +button.menu-button { + font-family: FiraSans-SemiBold; + font-size: 15px; + width: 100%; + height: auto; + border-radius: 0; + padding: 6px; + text-align: left; + background-color: #c0c0c0; + border: none; +} + +button.menu-button:hover { + background-color: #00B4EF; + border: none; +} + +button.menu-button:active { + background-color: #00B4EF; + border: none; +} + +div.menu-item { + width: 100%; +} + +div.menu-item-caption { + float: left; +} + +div.menu-item-shortcut { + float: right; +} diff --git a/tools/ci-scripts/upload.py b/tools/ci-scripts/upload.py index f43fbfd574..ab96e4ba24 100644 --- a/tools/ci-scripts/upload.py +++ b/tools/ci-scripts/upload.py @@ -6,19 +6,18 @@ import boto3 import glob from github import Github - def main(): - bucket_name = os.environ['BUCKET_NAME'] + bucket_name = os.environ['UPLOAD_BUCKET'] upload_prefix = os.environ['UPLOAD_PREFIX'] release_number = os.environ['RELEASE_NUMBER'] - full_prefix = upload_prefix + '/' + release_number[0:-2] + '/' + release_number + full_prefix = upload_prefix + '/' + release_number S3 = boto3.client('s3') path = os.path.join(os.getcwd(), os.environ['ARTIFACT_PATTERN']) files = glob.glob(path, recursive=False) for archiveFile in files: filePath, fileName = os.path.split(archiveFile) S3.upload_file(os.path.join(filePath, fileName), bucket_name, full_prefix + '/' + fileName) - print("Uploaded Artifact to S3: https://{}.s3-us-west-2.amazonaws.com/{}/{}".format(bucket_name, full_prefix, fileName)) + print("Uploaded Artifact to S3: https://{}.s3-eu-west-3.amazonaws.com/{}/{}".format(bucket_name, full_prefix, fileName)) print("Finished") main()