diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml new file mode 100644 index 0000000000..527f095df8 --- /dev/null +++ b/.github/workflows/qatest.yaml @@ -0,0 +1,168 @@ +name: Run QA Test # Runs automated tests on a self-hosted QA machine + +on: + workflow_run: + workflows: ["Build"] + types: + - completed + +concurrency: + group: qa-test-run + cancel-in-progress: true # Cancels any queued job when a new one starts + +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: + runs-on: [self-hosted, qa-machine] + # Run test only on successful builds of Second_Life_X branches + if: > + github.event.workflow_run.conclusion == 'success' && + ( + startsWith(github.ref, 'refs/tags/Second_Life') + ) + + steps: + - name: Temporarily Allow PowerShell Scripts (Process Scope) + run: | + Set-ExecutionPolicy RemoteSigned -Scope Process -Force + + - name: Verify viewer-sikulix-main Exists + run: | + if (-Not (Test-Path -Path 'C:\viewer-sikulix-main')) { + Write-Host '❌ Error: viewer-sikulix not found on runner!' + exit 1 + } + Write-Host '✅ viewer-sikulix is already available.' + + - name: Fetch & Download Windows Installer Artifact + shell: pwsh + run: | + $BUILD_ID = "${{ github.event.workflow_run.id }}" + $ARTIFACTS_URL = "https://api.github.com/repos/secondlife/viewer/actions/runs/$BUILD_ID/artifacts" + + # 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 "Windows-installer" }).archive_download_url + + if (-Not $ARTIFACT_NAME) { + Write-Host "❌ Error: Windows-installer 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 Windows-installer.zip" + exit 1 + } + + - name: Extract Installer & Locate Executable + shell: pwsh + run: | + # Explicitly set BUILD_ID again (since it does not appear to persist across steps) + $BUILD_ID = "${{ github.event.workflow_run.id }}" + $ExtractPath = "$env:TEMP\secondlife-build-$BUILD_ID" + $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 Using Task Scheduler (Bypass UAC) + shell: pwsh + run: | + $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 + 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 Task Scheduler Entry + shell: pwsh + run: | + Unregister-ScheduledTask -TaskName "SilentSLInstaller" -Confirm:$false + Write-Host "✅ Task Scheduler entry removed." + + - name: Delete Installer ZIP + shell: pwsh + run: | + # Explicitly set BUILD_ID again + $BUILD_ID = "${{ github.event.workflow_run.id }}" + $DeletePath = "$env:TEMP\secondlife-build-$BUILD_ID\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 + run: | + Write-Host "Running QA Test script..." + python C:\viewer-sikulix-main\runTests.py + + # - name: Upload Test Results + # uses: actions/upload-artifact@v3 + # with: + # name: test-results + # path: C:\viewer-sikulix-main\regressionTest\test_results.html diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 67d713db1f..759638b956 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -262,6 +262,8 @@ public: void setMediaURLResetTimer(F32 time); virtual void setLocalID(S32 local_id); + void setRegionID(const LLUUID& id) { mRegionID = id; } + const LLUUID& getRegionID() const { return mRegionID; } // blow away all the extra stuff lurking in parcels, including urls, access lists, etc void clearParcel(); @@ -651,6 +653,7 @@ public: S32 mLocalID; LLUUID mBanListTransactionID; LLUUID mAccessListTransactionID; + LLUUID mRegionID; std::map mAccessList; std::map mBanList; std::map mTempBanList; diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index d632604444..2ee0a3a454 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -1405,6 +1405,7 @@ char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->ge char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience"); char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID"); char const* const _PREHASH_LargeGenericMessage = LLMessageStringTable::getInstance()->getString("LargeGenericMessage"); +char const* const _PREHASH_MetaData = LLMessageStringTable::getInstance()->getString("MetaData"); // Aurora Sim char const* const _PREHASH_RegionSizeX = LLMessageStringTable::getInstance()->getString("RegionSizeX"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index a10827f98f..72f367b001 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -1405,6 +1405,7 @@ extern char const* const _PREHASH_HoverHeight; extern char const* const _PREHASH_Experience; extern char const* const _PREHASH_ExperienceID; extern char const* const _PREHASH_LargeGenericMessage; +extern char const* const _PREHASH_MetaData; // Aurora Sim extern char const* const _PREHASH_RegionSizeX; diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 7929c1e99a..5e223aa2ca 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -651,6 +651,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, U8 *binary_bucket, S32 binary_bucket_size, LLHost &sender, + LLSD metadata, LLUUID aux_id) { LLChat chat; @@ -707,6 +708,28 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, bool is_afk = gAgent.getAFK(); // + /*** + * The simulator may have flagged this sender as a bot, if the viewer would like to display + * the chat text in a different color or font, the below code is how the viewer can + * tell if the sender is a bot. + *----------------------------------------------------- + bool is_bot = false; + if (metadata.has("sender")) + { // The server has identified this sender as a bot. + is_bot = metadata["sender"]["bot"].asBoolean(); + } + *----------------------------------------------------- + */ + + std::string notice_name; + LLSD notice_args; + if (metadata.has("notice")) + { // The server has injected a notice into the IM conversation. + // These will be things like bot notifications, etc. + notice_name = metadata["notice"]["id"].asString(); + notice_args = metadata["notice"]["data"]; + } + chat.mMuted = is_muted; chat.mFromID = from_id; chat.mFromName = name; @@ -886,6 +909,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, position, false, timestamp, + LLUUID::null, + "", false, keyword_alert_performed); @@ -918,6 +943,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, position, false, 0, + LLUUID::null, + "", true ); // @@ -942,6 +969,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, position, false, 0, + LLUUID::null, + "", true); LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); } @@ -963,7 +992,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else { - // standard message, not from system + // standard message, server may have injected a notice into the conversation. std::string saved; if (offline == IM_OFFLINE) { @@ -1026,8 +1055,17 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, region_message = true; } } - gIMMgr->addMessage( - session_id, + + std::string real_name; + + if (!notice_name.empty()) + { // The simulator has injected some sort of notice into the conversation. + // findString will only replace the contents of buffer if the notice_id is found. + LLTrans::findString(buffer, notice_name, notice_args); + real_name = SYSTEM_FROM; + } + + gIMMgr->addMessage(session_id, from_id, name, buffer, @@ -1039,6 +1077,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, position, region_message, timestamp, + LLUUID::null, + real_name, false, keyword_alert_performed); } @@ -1756,6 +1796,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, position, false, timestamp, + LLUUID::null, + "", false, keyword_alert_performed); } @@ -2379,6 +2421,12 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) from_group = message_data["from_group"].asString() == "Y"; } + LLSD metadata; + if (message_data.has("metadata")) + { + metadata = message_data["metadata"]; + } + EInstantMessage dialog = static_cast(message_data["dialog"].asInteger()); LLUUID session_id = message_data["transaction-id"].asUUID(); if (session_id.isNull() && dialog == IM_FROM_TASK) @@ -2406,6 +2454,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) local_bin_bucket.data(), S32(local_bin_bucket.size()), local_sender, + metadata, message_data["asset_id"].asUUID()); }); diff --git a/indra/newview/llimprocessing.h b/indra/newview/llimprocessing.h index 030d28b198..66ffc59ae0 100644 --- a/indra/newview/llimprocessing.h +++ b/indra/newview/llimprocessing.h @@ -48,6 +48,7 @@ public: U8 *binary_bucket, S32 binary_bucket_size, LLHost &sender, + LLSD metadata, LLUUID aux_id = LLUUID::null); // Either receives list of offline messages from 'ReadOfflineMsgs' capability diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index b8448d789f..795a1bdade 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3446,11 +3446,18 @@ void LLIMMgr::addMessage( const LLUUID& region_id, const LLVector3& position, bool is_region_msg, - U32 timestamp, // May be zero + U32 timestamp, // May be zero + LLUUID display_id, + std::string_view display_name, bool is_announcement, // Special parameter indicating announcements bool keyword_alert_performed) // Pass info if keyword alert has been performed { LLUUID other_participant_id = target_id; + std::string message_display_name = (display_name.empty()) ? from : std::string(display_name); + if (display_id.isNull() && (display_name.empty())) + { + display_id = other_participant_id; + } LLUUID new_session_id = session_id; if (new_session_id.isNull()) @@ -3603,7 +3610,7 @@ void LLIMMgr::addMessage( // Configurable IM sounds // //Play sound for new conversations - // if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation"))) + // if (!skip_message && !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation"))) // Option to automatically ignore and leave all conference (ad-hoc) chats static LLCachedControl ignoreAdHocSessions(gSavedSettings, "FSIgnoreAdHocSessions"); @@ -3712,8 +3719,8 @@ void LLIMMgr::addMessage( if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) { // Added is_announcement parameter - //LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp); - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp, is_announcement, keyword_alert_performed); + //LLIMModel::instance().addMessage(new_session_id, message_display_name, display_id, msg, true, is_region_msg, timestamp); + LLIMModel::instance().addMessage(new_session_id, message_display_name, display_id, msg, true, is_region_msg, timestamp, is_announcement, keyword_alert_performed); } // Open conversation floater if offline messages are present @@ -4606,6 +4613,8 @@ void typingNameCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLVector3::zero, false, 0, + LLUUID::null, + "", true ); } @@ -4679,6 +4688,8 @@ void typingNameCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLVector3::zero, false, 0, + LLUUID::null, + "", true ); @@ -4702,6 +4713,8 @@ void typingNameCallback(const LLUUID& av_id, const LLAvatarName& av_name, const LLVector3::zero, false, 0, + LLUUID::null, + "", true); LLGiveInventory::doGiveInventoryItem(av_id, item, session_id); } diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 1debfcdf0d..287e0ef78f 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -414,6 +414,8 @@ public: const LLVector3& position = LLVector3::zero, bool is_region_msg = false, U32 timestamp = 0, + LLUUID display_id = LLUUID::null, + std::string_view display_name = "", bool is_announcement = false, // Special parameter indicating announcement bool keyword_alert_performed = false // Pass info if keyword alert has been performed ); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5bf126f7b4..24d7da0fb2 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2531,6 +2531,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) EInstantMessage dialog = (EInstantMessage)d; LLHost sender = msg->getSender(); + LLSD metadata; + if (msg->getNumberOfBlocksFast(_PREHASH_MetaData) > 0) + { + S32 metadata_size = msg->getSizeFast(_PREHASH_MetaData, 0, _PREHASH_Data); + std::string metadata_buffer; + metadata_buffer.resize(metadata_size, 0); + + msg->getBinaryDataFast(_PREHASH_MetaData, _PREHASH_Data, &metadata_buffer[0], metadata_size, 0, metadata_size ); + std::stringstream metadata_stream(metadata_buffer); + if (LLSDSerialize::fromBinary(metadata, metadata_stream, metadata_size) == LLSDParser::PARSE_FAILURE) + { + metadata.clear(); + } + } + LLIMProcessing::processNewMessage(from_id, from_group, to_id, @@ -2545,7 +2560,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) position, binary_bucket, binary_bucket_size, - sender); + sender, + metadata); } void send_do_not_disturb_message (LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 460f775ea4..cb9824f5b9 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1382,12 +1382,12 @@ const S32 LLViewerParcelMgr::getAgentParcelId() const return INVALID_PARCEL_ID; } -void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region) +void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel) { if(!parcel) return; - LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); + LLViewerRegion *region = LLWorld::getInstance()->getRegionFromID(parcel->getRegionID()); if (!region) return; @@ -1749,10 +1749,16 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Actually extract the data. if (parcel) { + // store region_id in the parcel so we can find it again later + LLViewerRegion* parcel_region = LLWorld::getInstance()->getRegion(msg->getSender()); + if (parcel_region) + { + parcel->setRegionID(parcel_region->getRegionID()); + } + if (local_id == parcel_mgr.mAgentParcel->getLocalID()) { // Parcels in different regions can have same ids. - LLViewerRegion* parcel_region = LLWorld::getInstance()->getRegion(msg->getSender()); LLViewerRegion* agent_region = gAgent.getRegion(); if (parcel_region && agent_region && parcel_region->getRegionID() == agent_region->getRegionID()) { diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 57c88a656d..c2d19b5fcd 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -233,7 +233,7 @@ public: // containing the southwest corner of the selection. // If want_reply_to_update, simulator will send back a ParcelProperties // message. - void sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region = false); + void sendParcelPropertiesUpdate(LLParcel* parcel); // Takes an Access List flag, like AL_ACCESS or AL_BAN void sendParcelAccessListUpdate(U32 which); diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index 57e5aee6cd..28bd2cfff8 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -3725,6 +3725,10 @@ Hvis du bliver ved med at modtage denne besked, kontakt venligst [SUPPORT_SITE]. Konference med [AGENT_NAME] + +Du chatter med en bot, [NAME]. Del ikke personlige oplysninger. +Læs mere på https://second.life/scripted-agents. + (IM session eksisterer ikke) diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 69f1e0fe79..74fa5e4c3a 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -4916,6 +4916,10 @@ Bitte installieren Sie den Viewer von [DOWNLOAD_URL] erneut und wenden Sie sich Inventarordner „[ITEM_NAME]“ angeboten + + Sie chatten mit einem Bot, [NAME]. Geben Sie keine persönlichen Informationen weiter. +Erfahren Sie mehr unter https://second.life/scripted-agents. + Objekte aus dem Inventar hier her ziehen diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index a0315d98c2..e5b8a0ee86 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2232,6 +2232,10 @@ Please reinstall viewer from [DOWNLOAD_URL] and contact [SUPPORT_SITE] if issue Inventory item offered to [NAME] + + You are chatting with a bot, [NAME]. Do not share any personal information. +Learn more at https://second.life/scripted-agents. + Drag items from inventory here diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index 891514a02a..e13bf741bb 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -4584,6 +4584,10 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE]. Carpeta del inventario '[ITEM_NAME]' ofrecida + + Estás conversando con un bot, [NAME]. No compartas información personal. +Más información en https://second.life/scripted-agents. + Ofrecido ítem de inventario a [NAME] diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 9b83381759..18f025ce59 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -4846,6 +4846,10 @@ Veuillez réinstaller la visionneuse à partir de [DOWNLOAD_URL] et contacter [S Dossier de l’inventaire [ITEM_NAME] offert + + Vous discutez avec un bot, [NAME]. Ne partagez pas d’informations personnelles. +En savoir plus sur https://second.life/scripted-agents. + Article d'inventaire offert à [NAME] diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 05a5727658..303d09e3bc 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -4756,6 +4756,10 @@ Reinstallare il browser da [DOWNLOAD_URL] e contattare [SUPPORT_SITE] se il prob Offerta cartella '[ITEM_NAME]' da inventario + + Stai parlando con un bot, [NAME]. Non condividere informazioni personali. +Scopri di più su https://second.life/scripted-agents. + Offerto oggetto da inventario a [NAME] diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 9520ef6430..86c2ede56b 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -4682,6 +4682,10 @@ www.secondlife.com から最新バージョンをダウンロードしてくだ インベントリフォルダー '[ITEM_NAME]' を送りました + +[NAME]とチャットしています。個人情報を共有しないでください。 +詳細は https://second.life/scripted-agents をご覧ください。 + インベントリからここにアイテムをドラッグします diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index 0489798959..208a5877ee 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -4751,6 +4751,10 @@ Zainstaluj ponownie przeglądarkę z [DOWNLOAD_URL] i skontaktuj się z [SUPPORT Zaoferowano przedmiot dla [NAME] + +Rozmawiasz z botem [NAME]. Nie udostępniaj żadnych danych osobowych. +Dowiedz się więcej na https://second.life/scripted-agents. + Przeciągaj tutaj rzeczy z Szafy diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 7233dba5b9..f908c4f93a 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -4856,6 +4856,10 @@ https://www.firestormviewer.org/support за помощь в решении эт Предложен элемент инвентаря [NAME] + +Вы общаетесь с ботом [NAME]. Не передавайте личные данные. +Подробнее на https://second.life/scripted-agents. + Перетащите элементы из инвентаря сюда diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 2e27028685..8dd479f377 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -4579,6 +4579,10 @@ Bu iletiyi almaya devam ederseniz, lütfen [SUPPORT_SITE] bölümüne başvurun. "[ITEM_NAME]" envanter klasörü sunuldu + +Bir bot ile sohbet ediyorsunuz, [NAME]. Kişisel bilgilerinizi paylaşmayın. +Daha fazla bilgi için: https://second.life/scripted-agents. + Envanterinizden buraya öğeler sürükleyin diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index d3f1fc5978..e738b2cf90 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -5091,6 +5091,10 @@ support@secondlife.com. 庫存物件已傳送給 [NAME] + +您正在与人工智能机器人 [NAME] 聊天。请勿分享任何个人信息。 +了解更多:https://second.life/scripted-agents。 + 將庫存物件拖拽到這裡