# Conflicts:
#	indra/newview/skins/default/xui/zh/strings.xml
master
Ansariel 2025-06-07 17:50:44 +02:00
commit 4cfdea8395
111 changed files with 1479 additions and 346 deletions

View File

@ -308,7 +308,17 @@ jobs:
if: ${{ matrix.variant == 'avx' }}
shell: bash
run: echo "EXTRA_ARGS=${{ env.EXTRA_ARGS }} --avx2" >> $GITHUB_ENV
- name: Add custom UA string if provided
env:
FS_PF_UA: ${{ secrets.FS_PF_UA }}
run: |
if [ -n "${FS_PF_UA}" ]; then
echo "EXTRA_ARGS=${{ env.EXTRA_ARGS }} -DFS_PF_USER_AGENT=\"${FS_PF_UA}\"" >> $GITHUB_ENV
echo "Building with custom user-agent string."
else
echo "No custom user-agent string provided."
fi
shell: bash
- name: Clean up packages to give more space
run: rm *${{ env.fallback_platform }}*bz2
shell: bash

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -661,6 +661,7 @@ void LLSettingsSky::blend(LLSettingsBase::ptr_t &end, F64 blendf)
mHasLegacyHaze |= lerp_legacy_float(mHazeDensity, mLegacyHazeDensity, other->mHazeDensity, other->mLegacyHazeDensity, 0.7f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_float(mDistanceMultiplier, mLegacyDistanceMultiplier, other->mDistanceMultiplier, other->mLegacyDistanceMultiplier, 0.8f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_float(mDensityMultiplier, mLegacyDensityMultiplier, other->mDensityMultiplier, other->mLegacyDensityMultiplier, 0.0001f, (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mAmbientColor, mLegacyAmbientColor, other->mAmbientColor, other->mLegacyAmbientColor, LLColor3(0.25f, 0.25f, 0.25f), (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mBlueHorizon, mLegacyBlueHorizon, other->mBlueHorizon, other->mLegacyBlueHorizon, LLColor3(0.4954f, 0.4954f, 0.6399f), (F32)blendf);
mHasLegacyHaze |= lerp_legacy_color(mBlueDensity, mLegacyBlueDensity, other->mBlueDensity, other->mLegacyBlueDensity, LLColor3(0.2447f, 0.4487f, 0.7599f), (F32)blendf);

View File

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

View File

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

View File

@ -54,7 +54,7 @@ include(jemalloc)
include(Discord)
# <FS:ND> if using ndPhysicsstub this variable will be unset, we don't need to build any stub code viewer side in that case
if( LLPHYSICSEXTENSIONS_SRC_DIR )
if (LLPHYSICSEXTENSIONS_SRC_DIR)
# </FS:ND>
if (NOT HAVOK_TPV)
@ -81,7 +81,7 @@ if (NOT HAVOK_TPV)
endif (NOT HAVOK_TPV)
# <FS:ND>
endif( LLPHYSICSEXTENSIONS_SRC_DIR )
endif (LLPHYSICSEXTENSIONS_SRC_DIR)
# </FS:ND>
set(viewer_SOURCE_FILES
@ -128,7 +128,7 @@ set(viewer_SOURCE_FILES
fsfloaternearbychat.cpp
fsfloaterpartialinventory.cpp
fsfloaterplacedetails.cpp
fsfloaterposer.cpp
fsfloaterposer.cpp
fsfloaterposestand.cpp
fsfloaterprotectedfolders.cpp
fsfloaterradar.cpp
@ -141,7 +141,7 @@ set(viewer_SOURCE_FILES
fsfloatervramusage.cpp
fsfloaterwearablefavorites.cpp
fsfloaterwhitelisthelper.cpp
fsjointpose.cpp
fsjointpose.cpp
fskeywords.cpp
fslslbridge.cpp
fslslbridgerequest.cpp
@ -163,8 +163,8 @@ set(viewer_SOURCE_FILES
fspanelradar.cpp
fsparticipantlist.cpp
fspose.cpp
fsposeranimator.cpp
fsposingmotion.cpp
fsposeranimator.cpp
fsposingmotion.cpp
fsprimfeedauth.cpp
fsradar.cpp
fsradarentry.cpp
@ -174,7 +174,7 @@ set(viewer_SOURCE_FILES
fsscriptlibrary.cpp
fsscrolllistctrl.cpp
fsslurlcommand.cpp
fsvirtualtrackpad.cpp
fsvirtualtrackpad.cpp
fsworldmapmessage.cpp
lggbeamcolormapfloater.cpp
lggbeammapfloater.cpp
@ -194,10 +194,12 @@ set(viewer_SOURCE_FILES
vjlocalmeshimportdae.cpp
gltfscenemanager.cpp
gltf/asset.cpp
gltf/accessor.cpp
gltf/primitive.cpp
gltf/animation.cpp
# <FS:Ansariel> Group GLTF files into their subfolders
#gltf/asset.cpp
#gltf/accessor.cpp
#gltf/primitive.cpp
#gltf/animation.cpp
# </FS:Ansariel> Group GLTF files into their subfolders
groupchatlistener.cpp
llaccountingcostmanager.cpp
llaisapi.cpp
@ -885,6 +887,18 @@ set(viewer_SOURCE_FILES
NACLfloaterexploresounds.cpp
)
# <FS:Ansariel> Group GLTF files into their subfolders
set(viewer_GLTF_SOURCE_FILES
gltf/asset.cpp
gltf/accessor.cpp
gltf/primitive.cpp
gltf/animation.cpp
)
source_group("Source Files\\GLTF" FILES ${viewer_GLTF_SOURCE_FILES})
list(APPEND viewer_SOURCE_FILES ${viewer_GLTF_SOURCE_FILES})
# </FS:Ansariel> Group GLTF files into their subfolders
if (OPENSIM)
list(APPEND viewer_SOURCE_FILES
fsgridhandler.cpp
@ -949,7 +963,7 @@ set(viewer_HEADER_FILES
fsfloaternearbychat.h
fsfloaterpartialinventory.h
fsfloaterplacedetails.h
fsfloaterposer.h
fsfloaterposer.h
fsfloaterposestand.h
fsfloaterprotectedfolders.h
fsfloaterradar.h
@ -985,8 +999,8 @@ set(viewer_HEADER_FILES
fspanelradar.h
fsparticipantlist.h
fspose.h
fsposeranimator.h
fsposingmotion.h
fsposeranimator.h
fsposingmotion.h
fsprimfeedauth.h
fsradar.h
fsradarentry.h
@ -997,7 +1011,7 @@ set(viewer_HEADER_FILES
fsscrolllistctrl.h
fsslurl.h
fsslurlcommand.h
fsvirtualtrackpad.h
fsvirtualtrackpad.h
fsworldmapmessage.h
lggbeamcolormapfloater.h
lggbeammapfloater.h
@ -1017,11 +1031,13 @@ set(viewer_HEADER_FILES
gltfscenemanager.h
groupchatlistener.h
gltf/asset.h
gltf/accessor.h
gltf/buffer_util.h
gltf/primitive.h
gltf/animation.h
# <FS:Ansariel> Group GLTF files into their subfolders
#gltf/asset.h
#gltf/accessor.h
#gltf/buffer_util.h
#gltf/primitive.h
#gltf/animation.h
# </FS:Ansariel> Group GLTF files into their subfolders
llaccountingcost.h
llaccountingcostmanager.h
llaisapi.h
@ -1710,6 +1726,19 @@ set(viewer_HEADER_FILES
list(APPEND viewer_SOURCE_FILES llperfstats.cpp)
list(APPEND viewer_HEADER_FILES llperfstats.h)
# <FS:Ansariel> Group GLTF files into their subfolders
set(viewer_GLTF_HEADER_FILES
gltf/asset.h
gltf/accessor.h
gltf/buffer_util.h
gltf/primitive.h
gltf/animation.h
)
source_group("Header Files\\GLTF" FILES ${viewer_GLTF_HEADER_FILES})
list(APPEND viewer_HEADER_FILES ${viewer_GLTF_HEADER_FILES})
# </FS:Ansariel> Group GLTF files into their subfolders
if (USE_BUGSPLAT)
list(APPEND viewer_SOURCE_FILES
bugsplatattributes.cpp

View File

@ -26366,6 +26366,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>FSManipShowJointMarkers</key>
<map>
<key>Comment</key>
<string>Show small markers where the selectable joints are.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSLocalMeshApplyJointOffsets</key>
<map>
<key>Comment</key>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -102,6 +102,7 @@
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
#include "rlvactions.h"
#include "rlvhandler.h"
#include "rlvlocks.h"
#include "rlvmodifiers.h"
// [/RLVa:KB]
// <FS:CR> Aurora Sim
@ -5302,6 +5303,18 @@ void LLSelectMgr::sendDetach()
return;
}
// [RLVa:KB]
if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
{
LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
RlvSelectHasLockedAttach f;
if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, false) != NULL) )
{
return;
}
}
// [/RLVa:KB]
sendListToRegions(
"ObjectDetach",
packAgentAndSessionID,

View File

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

View File

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

View File

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

View File

@ -3476,6 +3476,15 @@ void handle_object_tex_refresh(LLViewerObject* object, LLSelectNode* node)
LLViewerTexture* spec_img = object->getTESpecularMap(i);
faces_per_texture[spec_img->getID()].push_back(i);
}
LLPointer<LLGLTFMaterial> mat = object->getTE(i)->getGLTFRenderMaterial();
if (mat.notNull())
{
for (U32 j = 0; j < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++j)
{
faces_per_texture[mat->mTextureId[j]].push_back(i);
}
}
}
map_t::iterator it;

View File

@ -1498,6 +1498,10 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
// <FS:Ansariel> Fast cache stats
sNumFastCacheReads++;
// </FS:Ansariel>
// <FS:Ansariel> Fix fast cache
if (timer.getElapsedTimeF32() > max_time)
break;
// </FS:Ansariel>
}
mFastCacheList.erase(mFastCacheList.begin(), enditer);
return timer.getElapsedTimeF32();
@ -1609,7 +1613,9 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
LLTimer timer;
//loading from fast cache
updateImagesLoadingFastCache(max_time);
// <FS:Ansariel> Fix fast cache
//updateImagesLoadingFastCache(max_time);
max_time -= updateImagesLoadingFastCache(max_time);
// Update texture stats and priorities
std::vector<LLPointer<LLViewerFetchedTexture> > image_list;

View File

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

View File

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

View File

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

View File

@ -252,11 +252,12 @@
Steuerkugel-Sensitivität:
</text>
<slider name="trackpad_sensitivity_slider" tool_tip="Stellt die Sensitivität der Steuerkugel ein"/>
<check_box name="natural_direction_checkbox" label="Natürl. Ausrichtung verw." tool_tip="Das Skelett besitzt standardmäßig unnatürliche Gelenk-Rotationen, was das Posieren erschwert. Falls aktiviert, werden die Gelenke in eine natürlichere Rotation versetzt."/>
<check_box name="stop_posing_on_close_checkbox" label="Beim Schließen stoppen" tool_tip="Die Pose beim Schließen nicht zu stoppen kann hilfreich sein, um die bisher getätigte Arbeit nicht zu verlieren."/>
<check_box name="reset_base_rotation_on_edit_checkbox" label="Basis-Rot. beim Edit. zurück." tool_tip="Wenn das erste Mal eine Pose bearbeitet wird, diese auf Null zurücksetzen. Hierdurch eine eine komplette Pose und nicht nur die Differenz gespeichert werden. Ein grüner Haken erscheint neben jedem Gelenk, dass auf Null-basierend exportiert wurde."/>
<check_box name="also_save_bvh_checkbox" label="BHV beim Speichern erst." tool_tip="Wenn die Pose gespeichert wird, wird ebenfalls eine BHV-Datei erstellt, die via Bauen > Hochladen > Animation hochgeladen und zum Posieren vom eigenen Avatar oder anderen Avataren verwendet werden kann. Hierzu muss die Basis der Gelenke auf Null gesetzt werden, da BHV nicht von anderen Posen abgeleitet wird."/>
<check_box name="confirm_overwrite_on_save_checkbox" label="Überschreiben bestätigen" tool_tip="Wenn die Pose gespeichert wird und die Datei bereits existiert, muss der Speichern-Button erneut geklickt werden um zu bestätigen, dass Sie die Datei überschreiben möchten."/>
<check_box name="natural_direction_checkbox" label="Natürl. Ausrichtung verw." tool_tip="Das Skelett besitzt standardmäßig unnatürliche Gelenk-Rotationen, was das Posieren erschwert. Falls aktiviert, werden die Gelenke in eine natürlichere Rotation versetzt."/>
<check_box name="show_joint_markers_checkbox" label="Gelenk-Marker anzeigen" tool_tip="Zeigt Indikatoren an, um das Auswählen von Gelenken beim Posieren zu vereinfachen."/>
</panel>
</tab_container>
<button name="toggleVisualManipulators" tool_tip="Visuelle Manipulatoren an-/ausschalten" />

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_translation_settings" title="Übersetzungseinstellungen für Chats">
<string name="azure_api_key_not_verified">
Azure-Service-Identifikator nicht verifiziert. Versuchen Sie es erneut.
Azure-Service-Identifikator nicht verifiziert. Status: [STATUS]. Bitte überprüfen Sie Ihre Einstellungen und versuchen Sie es erneut.
</string>
<string name="google_api_key_not_verified">
Google-API-Schlüssel nicht verifiziert. Versuchen Sie es erneut.
Google-API-Schlüssel nicht verifiziert. Status: [STATUS]. Bitte überprüfen Sie Ihren Schlüssel und versuchen Sie es erneut.
</string>
<string name="deepl_api_key_not_verified">
DeepL-Authentifizierungsschlüssel nicht verifiziert. Versuchen Sie es erneut.
DeepL-Authentifizierungsschlüssel nicht verifiziert. Status: [STATUS]. Bitte überprüfen Sie Ihren Schlüssel und versuchen Sie es erneut.
</string>
<string name="azure_api_key_verified">
Azure-Service-Identifikator verifiziert.

View File

@ -71,6 +71,8 @@
<scroll_list.columns label="" name="icon"/>
<scroll_list.columns label="" name="sim_name"/>
</scroll_list>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Standort:
</text>

View File

@ -15,6 +15,10 @@
<check_box label="Guide anzeigen" name="show_guides" tool_tip="Zeigt Aufnahme-Guide (Drittel-Regel) innerhalb des Aufnahmebereichs an."/>
<button label="Aktualisieren" name="new_snapshot_btn" tool_tip="Zum Aktualisieren klicken"/>
<button label="Vorschau" name="big_preview_btn" tool_tip="Klicken, um Vorschau ein-/auszuschalten"/>
<text name="store_label">
Teilen als:
</text>
<combo_box name="stores_combobox" tool_tip="Falls Ihnen einen oder mehrere Blogger-Bestände auf Primfeed zugewiesen sind, erscheinen diese hier."/>
<text name="description_label">
Beschreibung:
</text>

View File

@ -10,6 +10,8 @@
</name_list>
<button label="Hinzufügen..." name="add_estate_manager_btn"/>
<button label="Entfernen..." name="remove_estate_manager_btn"/>
<button label="Exportieren..." name="export_estate_manager_btn"/>
<button label="Importieren..." name="import_estate_manager_btn" tool_tip="Importiert eine CSV-Datei mit ausschließlich gültigen UUIDs - eine pro Zeile ohne extra Zeichen oder Formatierung"/>
</panel>
<panel label="Zulässig" name="allowed_panel">
<panel label="top_panel" name="allowed_search_panel">
@ -24,6 +26,8 @@
</name_list>
<button label="Hinzufügen..." name="add_allowed_avatar_btn"/>
<button label="Entfernen..." name="remove_allowed_avatar_btn"/>
<button label="Exportieren..." name="export_allowed_list_btn"/>
<button label="Importieren..." name="import_allowed_list_btn" tool_tip="Importiert eine CSV-Datei mit ausschließlich gültigen UUIDs - eine pro Zeile ohne extra Zeichen oder Formatierung"/>
</panel>
<panel label="Zulässige Gruppen" name="allowed_groups_panel">
<panel label="top_panel" name="allowed_group_search_panel">
@ -38,6 +42,8 @@
</name_list>
<button label="Hinzufügen..." name="add_allowed_group_btn"/>
<button label="Entfernen..." name="remove_allowed_group_btn"/>
<button label="Exportieren..." name="export_allowed_group_btn"/>
<button label="Importieren..." name="import_allowed_group_btn" tool_tip="Importiert eine CSV-Datei mit ausschließlich gültigen UUIDs - eine pro Zeile ohne extra Zeichen oder Formatierung"/>
</panel>
<panel label="Verbannt" name="banned_panel">
<panel label="top_panel" name="banned_search_panel">
@ -55,6 +61,8 @@
</name_list>
<button label="Hinzufügen..." name="add_banned_avatar_btn"/>
<button label="Entfernen..." name="remove_banned_avatar_btn"/>
<button label="Exportieren..." name="export_banned_avatar_btn"/>
<button label="Importieren..." name="import_banned_avatar_btn" tool_tip="Importiert eine CSV-Datei mit ausschließlich gültigen UUIDs - eine pro Zeile ohne extra Zeichen oder Formatierung"/>
</panel>
</tab_container>
</panel>

View File

@ -7279,4 +7279,16 @@ Ihre aktuelle Position: [AVATAR_POS]
<string name="Unlimited">
Unlimitiert
</string>
<string name="ListEmpty">
Liste is leer
</string>
<string name="NoValidUUIDs">
Keine gültigen UUIDs in importierter Datei gefunden.
</string>
<string name="ImportListTooLarge">
Zu viele Einträge. Die CSV-Datei hat [COUNT] Einträge, es sind aber nur [MAX] Plätze verfügbar.
</string>
<string name="ImportSuccessful">
[COUNT] Einträge erfolgreich verarbeitet.
</string>
</strings>

View File

@ -140,7 +140,7 @@ The Firestorm Development Team:
top_pad="4"
width="450"
wrap="true">
Angeldark Raymaker, Ansariel Hiller, ArminWeatherHax, Arrehn Oberlander, Beq Janus, Chanayane, Cinder Roxley, Hecklezz, Holy Gavenkrantz, Jessica Lyon, Kadah Coba, Kitty Barnett, Liny Odell, LordGregGreg Back, minerjr, Mobius Ryba, Nicky Dasmijn, PanteraPolnocy, ScentualLust, Selo Jacobus, SimonLsAlt, Tankmaster Finesmith, Techwolf Lupindo, Tonya Souther, Tozh Taurog, Vortex Saito, WoLf Loonie, Wolfspirit Magic, Yay N' Stuff (mygoditsfullofstars), and Zi Ree.
Angeldark Raymaker, Ansariel Hiller, ArminWeatherHax, Arrehn Oberlander, Ayane Lyla, Beq Janus, Cinder Roxley, Hecklezz, Holy Gavenkrantz, Jessica Lyon, Kadah Coba, Kitty Barnett, Liny Odell, LordGregGreg Back, minerjr, Mobius Ryba, Nicky Dasmijn, PanteraPolnocy, ScentualLust, Selo Jacobus, SimonLsAlt, Tankmaster Finesmith, Techwolf Lupindo, Tonya Souther, Tozh Taurog, Vortex Saito, WoLf Loonie, Wolfspirit Magic, Yay N' Stuff (mygoditsfullofstars), and Zi Ree.
</text>
<text
follows="top|left"
@ -165,7 +165,7 @@ Additional code generously contributed to Firestorm by:
top_pad="4"
width="450"
wrap="true">
Aira Yumi, Albatroz Hird, Alexie Birman, Andromeda Rage, Angus Boyd, Animats, Armin Weatherwax, Ayane Lyla, Casper Warden, Chalice Yao, Chaser Zaks, Chorazin Allen, Cron Stardust, Damian Zhaoying, Dan Threebeards, Darlcat, Dawa Gurbux, Dax Dupont, Denver Maksim, Dragonborn Forzane, Drake Arconis, Felyza Wishbringer, f0rbidden, Fractured Crystal, Geenz Spad, Gibson Firehawk, Hecklezz, Hitomi Tiponi, humbletim, Inusaito Sayori, Jean Severine, Katharine Berry, Kittin Ninetails, Kool Koolhoven, Lance Corrimal, Lassie, Latif Khalifa, Laurent Bechir, Logue Takacs, Magne Metaverse LLC, Magus Freston, Makidoll, Manami Hokkigai, MartinRJ Fayray, McCabe Maxstead, Melancholy Lemon, Melysmile, Mimika Oh, minerjr, Mister Acacia, MorganMegan, Morgan Pennent, Mysty Saunders, Nagi Michinaga, Name Short, nhede Core, NiranV Dean, Nogardrevlis Lectar, olizinha, Oren Hurvitz, paperwork, Penny Patton, Peyton Menges, programmtest, Qwerty Venom, rafak360, Rebecca Ashbourne, Revolution Smythe, Romka Swallowtail, Sahkolihaa Contepomi, sal Kaligawa, Samm Florian, Satomi Ahn, Sei Lisa, Sekkmer, Sempervirens Oddfellow, Shin Wasp, Shyotl Kuhr, Sione Lomu, Skills Hak, StarlightShining, Sunset Faulkes, Tapple Gao, Testicular Slingshot, Thickbrick Sleaford, Ubit Umarov, Vaalith Jinn, Vincent Sylvester, Whirly Fizzle, Xenhat Liamano, 小滢 Zi Ying, Zwagoth Klaar and others.
Aira Yumi, Albatroz Hird, Alexie Birman, Andromeda Rage, Angus Boyd, Animats, Armin Weatherwax, Casper Warden, Chalice Yao, Chaser Zaks, Chorazin Allen, Cron Stardust, Damian Zhaoying, Dan Threebeards, Darlcat, Dawa Gurbux, Dax Dupont, Denver Maksim, Dragonborn Forzane, Drake Arconis, Felyza Wishbringer, f0rbidden, Fractured Crystal, Geenz Spad, Gibson Firehawk, Hitomi Tiponi, humbletim, Inusaito Sayori, Jean Severine, Katharine Berry, Kittin Ninetails, Kool Koolhoven, Lance Corrimal, Lassie, Latif Khalifa, Laurent Bechir, Logue Takacs, Magne Metaverse LLC, Magus Freston, Makidoll, Manami Hokkigai, MartinRJ Fayray, McCabe Maxstead, Melancholy Lemon, Melysmile, Mimika Oh, Mister Acacia, MorganMegan, Morgan Pennent, Mysty Saunders, Nagi Michinaga, Name Short, nhede Core, NiranV Dean, Nogardrevlis Lectar, olizinha, OrangeStripyDog, Oren Hurvitz, paperwork, Penny Patton, Peyton Menges, programmtest, Qwerty Venom, rafak360, Rebecca Ashbourne, Revolution Smythe, Romka Swallowtail, Sahkolihaa Contepomi, sal Kaligawa, Samm Florian, Satomi Ahn, Sei Lisa, Sekkmer, Sempervirens Oddfellow, Shin Wasp, Shyotl Kuhr, Sione Lomu, Skills Hak, StarlightShining, Sunset Faulkes, Tapple Gao, Testicular Slingshot, Thickbrick Sleaford, Ubit Umarov, Vaalith Jinn, Vincent Sylvester, Whirly Fizzle, Xenhat Liamano, 小滢 Zi Ying, Zwagoth Klaar and others.
</text>
<text
follows="top|left"

View File

@ -2152,7 +2152,7 @@ Only large parcels can be listed in search.
name="Allowed_layout_panel"
follows="top|left"
left="10"
height="170"
height="185"
top_pad="8"
width="240">
<text
@ -2181,27 +2181,50 @@ Only large parcels can be listed in search.
width="230" />
<button
follows="bottom"
height="23"
height="30"
label="Add"
layout="topleft"
left="0"
name="add_allowed"
width="100" />
width="70" />
<button
follows="bottom"
height="23"
height="30"
label="Remove"
label_selected="Remove"
layout="topleft"
left_pad="10"
left_pad="5"
name="remove_allowed"
width="70" />
<button
enabled="false"
follows="bottom"
height="15"
label="Export"
label_selected="Export"
layout="topleft"
left_pad="5"
top_pad="-30"
name="export_allowed"
right="-10"
width="100" />
width="80" />
<button
enabled="false"
tool_tip="Import a CSV file containing only valid UUIDs - one per line, no extra characters or formatting."
follows="bottom"
height="15"
label="Import"
label_selected="Import"
layout="topleft"
top_pad="0"
name="import_allowed"
right="-10"
width="80" />
</panel>
<panel
name="Banned_layout_panel"
follows="top|right"
height="170"
height="185"
width="240"
left_pad="2">
<text
@ -2240,23 +2263,46 @@ Only large parcels can be listed in search.
</name_list>
<button
follows="bottom"
height="23"
height="30"
label="Add"
layout="topleft"
left="0"
name="add_banned"
width="100" />
width="70" />
<button
enabled="false"
follows="bottom"
height="23"
height="30"
label="Remove"
label_selected="Remove"
layout="topleft"
left_pad="10"
left_pad="5"
name="remove_banned"
width="70" />
<button
enabled="false"
follows="bottom"
height="15"
label="Export"
label_selected="Export"
layout="topleft"
left_pad="5"
top_pad="-30"
name="export_banned"
right="-10"
width="100" />
width="80" />
<button
enabled="false"
tool_tip="Import a CSV file containing only valid UUIDs - one per line, no extra characters or formatting."
follows="bottom"
height="15"
label="Import"
label_selected="Import"
layout="topleft"
top_pad="0"
name="import_banned"
right="-10"
width="80" />
</panel>
</panel>
<panel

View File

@ -4,9 +4,9 @@
help_topic="fs_area_search"
title="Area Search for Objects"
min_width="430"
min_height="395"
min_height="440"
width="610"
height="435"
height="440"
save_rect="true"
single_instance="true"
reuse_instance="false"
@ -33,7 +33,7 @@
left="0"
name="area_search_list_panel"
top="0"
height="435"
height="440"
width="610">
<panel.string name="ListedPendingTotalBlank">
Listed | Pending | Total
@ -395,7 +395,7 @@
name="filter_for_sale"
label="For Sale between"
top_pad="10"
width="120"/>
width="130"/>
<spinner
decimal_digits="0"
follows="left|top"
@ -435,7 +435,7 @@
follows="top|left"
left="15"
top_pad="25"
width="100">
width="115">
Mouse click action
</text>
<combo_box
@ -504,7 +504,7 @@
name="filter_distance"
label="Distance between"
top_pad="10"
width="120"/>
width="130"/>
<spinner
decimal_digits="0"
follows="left|top"

View File

@ -952,16 +952,6 @@ width="430">
function="Poser.CommitSpinner"
parameter="3"/>
</spinner>
<check_box
control_name="FSManipRotateJointUseNaturalDirection"
name="natural_direction_checkbox"
height="16"
label="Use natural alignment"
follows="left|top"
left="5"
tool_tip="The skeleton has unnatural joint rotations by default. This complicates posing. When checked, the joints will rotate in a more natural way."
top_pad="10"
width="134" />
<check_box
control_name="FSPoserStopPosingWhenClosed"
name="stop_posing_on_close_checkbox"
@ -1003,6 +993,26 @@ width="430">
tool_tip="When you save a pose, if the file already exists, you need to click the save button again to confirm you are sure you want to overwrite."
top_pad="5"
width="134" />
<check_box
control_name="FSManipRotateJointUseNaturalDirection"
name="natural_direction_checkbox"
height="16"
label="Use natural alignment"
follows="left|top"
left="5"
tool_tip="The skeleton has unnatural joint rotations by default. This complicates posing. When checked, the joints will rotate in a more natural way."
top_pad="5"
width="134" />
<check_box
control_name="FSManipShowJointMarkers"
name="show_joint_markers_checkbox"
height="16"
label="Show joint markers"
follows="left|top"
left="5"
tool_tip="Show small indicators to aid joint selection when visually posing."
top_pad="5"
width="134" />
</panel>
</tab_container>
<button

View File

@ -1592,7 +1592,7 @@
max_val="100000"
min_val="0"
width="53"
increment="0.01"/>
increment="1"/>
<button
follows="left|top"
name="Reset_Scaling_Factor"
@ -3122,7 +3122,7 @@
left_pad="0"
decimal_digits="0"
follows="left|top"
max_val="1"
max_val="10"
min_val="0"
width="53"
increment="1"/>
@ -4186,7 +4186,7 @@
max_val="1024"
min_val="0"
width="53"
increment=".0001"/>
increment=".001"/>
<button
follows="left|top"
name="Reset_IO_Axis"
@ -4235,7 +4235,7 @@
max_val="1024"
min_val="0"
width="53"
increment=".0001"/>
increment=".001"/>
<button
follows="left|top"
name="Reset_Tilt"
@ -4284,7 +4284,7 @@
max_val="1024"
min_val="0"
width="53"
increment=".0001"/>
increment=".001"/>
<button
follows="left|top"
name="Reset_Spin"
@ -4333,7 +4333,7 @@
max_val="1024"
min_val="0"
width="53"
increment=".0001"/>
increment=".001"/>
<button
follows="left|top"
name="Reset_Roll"
@ -4382,7 +4382,7 @@
max_val="1"
min_val="0"
width="53"
increment=".0001"/>
increment=".001"/>
<button
follows="left|top"
name="Reset_Zoom_Speed"
@ -4431,7 +4431,7 @@
max_val="100"
min_val="0"
width="53"
increment=".001"/>
increment="0.1"/>
<button
follows="left|top"
name="Reset_Feathering"

View File

@ -10,10 +10,10 @@
single_instance="true"
reuse_instance="true"
title="Share to Primfeed"
height="600"
height="638"
width="272">
<panel
height="590"
height="638"
width="272"
visible="true"
name="background"
@ -27,7 +27,7 @@
tab_height="21"
tab_position="top"
top="7"
height="570"
height="605"
follows="all"
halign="center">
<panel

View File

@ -504,7 +504,7 @@
</panel>
<panel
follows="right|top|bottom"
height="330"
height="235"
top_pad="0"
width="258"
name="layout_panel_4">
@ -626,6 +626,13 @@
<scroll_list.commit_callback
function="WMap.SearchResult" />
</scroll_list>
</panel>
<panel
follows="right|bottom"
height="95"
top_pad="0"
width="258"
name="layout_panel_7">
<text
type="string"
length="1"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<panel
height="540"
height="590"
width="272"
follows="all"
layout="topleft"
@ -192,6 +192,29 @@
width="100">
<button.commit_callback function="SocialSharing.BigPreview" />
</button>
<text
follows="left|top"
layout="topleft"
font="SansSerif"
height="16"
left="10"
name="store_label"
top_pad="8"
type="string">
Post as:
</text>
<combo_box
control_name="FSPrimfeedSelectedStore"
follows="left|top"
layout="topleft"
name="stores_combobox"
tool_tip="If you have one or more easy blogger stores assigned on Primfeed they will appear here."
top_pad="2"
left="10"
height="21"
width="235">
<!-- Initially empty; items will be populated at runtime -->
</combo_box>
<text
length="1"
follows="top|left|right"

View File

@ -85,7 +85,7 @@
left="10"
name="add_estate_manager_btn"
top_pad="6"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
@ -93,7 +93,24 @@
layout="topleft"
name="remove_estate_manager_btn"
left_pad="6"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
label="Export..."
layout="topleft"
name="export_estate_manager_btn"
left_pad="6"
width="100" />
<button
follows="left|top"
tool_tip="Import a CSV file containing only valid UUIDs - one per line, no extra characters or formatting."
height="23"
label="Import..."
layout="topleft"
name="import_estate_manager_btn"
left_pad="6"
width="100" />
</panel>
@ -186,7 +203,7 @@
left="10"
name="add_allowed_avatar_btn"
top_pad="6"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
@ -194,7 +211,24 @@
layout="topleft"
name="remove_allowed_avatar_btn"
left_pad="6"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
label="Export..."
layout="topleft"
name="export_allowed_list_btn"
left_pad="6"
width="100" />
<button
follows="left|top"
tool_tip="Import a CSV file containing only valid UUIDs - one per line, no extra characters or formatting."
height="23"
label="Import..."
layout="topleft"
name="import_allowed_list_btn"
left_pad="6"
width="100" />
</panel>
<!-- ============================= ALLOWED GROUPS tab ======================= -->
@ -285,7 +319,7 @@
left="10"
name="add_allowed_group_btn"
top_pad="6"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
@ -294,7 +328,26 @@
name="remove_allowed_group_btn"
left_pad="6"
top_delta="0"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
label="Export..."
layout="topleft"
name="export_allowed_group_btn"
left_pad="6"
top_delta="0"
width="100" />
<button
follows="left|top"
tool_tip="Import a CSV file containing only valid UUIDs - one per line, no extra characters or formatting."
height="23"
label="Import..."
layout="topleft"
name="import_allowed_group_btn"
left_pad="6"
top_delta="0"
width="100" />
</panel>
<!-- ================================ BANNED tab ============================ -->
@ -397,7 +450,7 @@
left="10"
name="add_banned_avatar_btn"
top_pad="6"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
@ -406,7 +459,26 @@
name="remove_banned_avatar_btn"
left_pad="6"
top_delta="0"
width="114" />
width="100" />
<button
follows="left|top"
height="23"
label="Export..."
layout="topleft"
name="export_banned_avatar_btn"
left_pad="6"
top_delta="0"
width="100" />
<button
follows="left|top"
tool_tip="Import a CSV file containing only valid UUIDs - one per line, no extra characters or formatting."
height="23"
label="Import..."
layout="topleft"
name="import_banned_avatar_btn"
left_pad="6"
top_delta="0"
width="100" />
</panel>

View File

@ -3320,4 +3320,10 @@ Your current position: [AVATAR_POS]
<string name="FSObjectInventoryElements">[NUM_ELEMENTS] Elements</string>
<string name="OpenSimInventoryValidationErrorGenericHelp">your Grid Operator's support team</string>
<string name="Unlimited">Unlimited</string>
<string name="ListEmpty">List is empty</string>
<string name="NoValidUUIDs">No valid UUIDs found in the imported file.</string>
<string name="ImportListTooLarge">Too many entries. The CSV file has [COUNT] entries and there are [MAX] slots available.</string>
<string name="ImportSuccessful">Successfully processed [COUNT] entries.</string>
</strings>

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_translation_settings" title="CONFIGURACIÓN DE LA TRADUCCIÓN DEL CHAT">
<string name="bing_api_key_not_verified">La appID de Bing no se ha confirmado. Vuelve a intentarlo.</string>
<string name="google_api_key_not_verified">La clave de API de Google no se ha confirmado. Vuelve a intentarlo.</string>
<string name="bing_api_key_verified">La appID de Bing ha sido confirmada.</string>
<string name="azure_api_key_not_verified">El identificador de servicio de Azure no se ha confirmado. Estado: [STATUS]. Vuelve a intentarlo.</string>
<string name="google_api_key_not_verified">La clave de API de Google no se ha confirmado. Estado: [STATUS]. Vuelve a intentarlo.</string>
<string name="deepl_api_key_not_verified">La clave de API de DeepL no se ha confirmado. Estado: [STATUS]. Vuelve a intentarlo.</string>
<string name="azure_api_key_verified">El identificador de servicio de Azure ha sido confirmado.</string>
<string name="google_api_key_verified">La clave de API de Google ha sido confirmada.</string>
<string name="deepl_api_key_verified">La clave de API de DeepL ha sido confirmada.</string>
<check_box label="Activar la traducción automática durante el chat" name="translate_chat_checkbox"/>
<text name="translate_language_label" left="25">
Traducir el chat al:

View File

@ -59,6 +59,8 @@
</combo_box>
<search_editor label="Regiones alfabéticamente" name="location" tool_tip="Escribe el nombre de una región"/>
<button label="Encontrar" name="DoSearch" tool_tip="Buscar una región"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Lugar:
</text>

View File

@ -463,6 +463,7 @@ musique :
<name_list name="AccessList" tool_tip="([LISTED] dans la liste, [MAX] max.)"/>
<button label="Ajouter" name="add_allowed"/>
<button label="Supprimer" label_selected="Supprimer" name="remove_allowed"/>
<button label="Exporter" label_selected="Exporter" name="export_allowed"/>
</panel>
<panel name="Banned_layout_panel">
<text label="Bannir" name="BanCheck">
@ -474,6 +475,7 @@ musique :
</name_list>
<button label="Ajouter" name="add_banned"/>
<button label="Supprimer" label_selected="Supprimer" name="remove_banned"/>
<button label="Exporter" label_selected="Exporter" name="export_banned"/>
</panel>
</panel>
<panel label="Expériences" name="land_experiences_panel"/>

View File

@ -243,11 +243,12 @@
Sensibilité du trackpad :
</text>
<slider name="trackpad_sensitivity_slider" tool_tip="Règle la sensibilité du trackpad"/>
<check_box name="natural_direction_checkbox" label="Utiliser l'alignement naturel" tool_tip="Le squelette a des rotations d'articulations non naturelles par défaut. Cela complique la pose. Si cette option est cochée, les articulations tourneront de manière plus naturelle."/>
<check_box name="stop_posing_on_close_checkbox" label="Arrêt pose si fermeture" tool_tip="Ne pas arrêter votre pose peut être utile si vous travaillez beaucoup et que vous ne voulez pas la perdre accidentellement."/>
<check_box name="reset_base_rotation_on_edit_checkbox" label="Réinitialisation de la rotation" tool_tip="Lorsque vous modifiez une rotation pour la première fois, la remet à zéro. Cela signifie que votre travail peut enregistrer une pose (et non une différence - voir charger/enregistrer). Une coche verte apparaît à côté de chaque articulation dont l'exportation a été remise à zéro."/>
<check_box name="also_save_bvh_checkbox" label="Ajouter BVH à l'enregis.**" tool_tip="Lorsque vous enregistrez votre pose, écrivez également un fichier BVH, qui peut être téléchargé via 'Construire > Charger > Animation' pour poser vous-même ou d'autres personnes dans le monde. Pour ce faire, les articulations doivent remettre leur « base » à zéro, car le BVH nécessite que l'on travaille sur l'original."/>
<check_box name="confirm_overwrite_on_save_checkbox" label="Confirmer l'écrasement" tool_tip="Lorsque vous enregistrez une pose, si le fichier existe déjà, vous devez cliquer à nouveau sur le bouton d'enregistrement pour confirmer que vous êtes sûr de vouloir l'écraser."/>
<check_box name="natural_direction_checkbox" label="Utiliser l'alignement naturel" tool_tip="Le squelette a des rotations d'articulations non naturelles par défaut. Cela complique la pose. Si cette option est cochée, les articulations tourneront de manière plus naturelle."/>
<check_box name="show_joint_markers_checkbox" label="Aff. marqueurs de jointure" tool_tip="Afficher de petits indicateurs pour faciliter la sélection des articulations lors de la pose visuelle."/>
</panel>
</tab_container>
<button name="toggleVisualManipulators" tool_tip="Activer et désactiver les manipulateurs visuels"/>

View File

@ -32,6 +32,8 @@
</combo_box>
<search_editor label="Nom de la région" name="location" tool_tip="Saisissez le nom d'une région"/>
<button label="Chercher" name="DoSearch" tool_tip="Rechercher une région"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label" width="90">Emplacement :</text>
<spinner left_pad="4" name="teleport_coordinate_x" width="44"/>
<spinner left_pad="4" name="teleport_coordinate_y" width="44"/>

View File

@ -10,6 +10,7 @@
</name_list>
<button label="Ajouter..." name="add_estate_manager_btn"/>
<button label="Supprimer..." name="remove_estate_manager_btn"/>
<button label="Exporter..." name="export_estate_manager_btn"/>
</panel>
<panel label="AUTORISÉ" name="allowed_panel">
<panel label="top_panel" name="allowed_search_panel">
@ -24,6 +25,7 @@
</name_list>
<button label="Ajouter..." name="add_allowed_avatar_btn"/>
<button label="Supprimer..." name="remove_allowed_avatar_btn"/>
<button label="Exporter..." name="export_allowed_list_btn"/>
</panel>
<panel label="GROUPES AUTORISÉS" name="allowed_groups_panel">
<panel label="top_panel" name="allowed_group_search_panel">
@ -38,6 +40,7 @@
</name_list>
<button label="Ajouter..." name="add_allowed_group_btn"/>
<button label="Supprimer" name="remove_allowed_group_btn"/>
<button label="Exporter..." name="export_allowed_group_btn"/>
</panel>
<panel label="INTERDIT" name="banned_panel">
<panel label="top_panel" name="banned_search_panel">
@ -55,6 +58,7 @@
</name_list>
<button label="Ajouter..." name="add_banned_avatar_btn"/>
<button label="Supprimer..." name="remove_banned_avatar_btn"/>
<button label="Exporter..." name="export_banned_avatar_btn"/>
</panel>
</tab_container>
</panel>

View File

@ -7153,4 +7153,16 @@ Votre position actuelle : [AVATAR_POS]
<string name="Unlimited">
Illimité
</string>
<string name="ListEmpty">
La liste est vide
</string>
<string name="NoValidUUIDs">
Le fichier importé ne contient aucun UUID valide.
</string>
<string name="ImportListTooLarge">
Trop d'entrées. Le fichier CSV contient [COUNT] entrées et il y a [MAX] emplacements disponibles.
</string>
<string name="ImportSuccessful">
Successfully processed [COUNT] entries.
</string>
</strings>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_translation_settings" title="Impostazioni Traduzione Chat">
<string name="azure_api_key_not_verified">Non è stato possibile verificare l'ID Azure. Riprova.</string>
<string name="google_api_key_not_verified">Non è stato possibile verificare la chiave API di Google. Riprova.</string>
<string name="deepl_api_key_not_verified">Impossibile verificare la chiave DeepL. Stato: [STATUS]. Riprova.</string>
<string name="azure_api_key_not_verified">Non è stato possibile verificare l'ID Azure. Stato: [STATUS]. Verifica le impostazioni e riprova.</string>
<string name="google_api_key_not_verified">Non è stato possibile verificare la chiave API di Google. Stato: [STATUS]. Verifica la chiave e riprova.</string>
<string name="deepl_api_key_not_verified">Impossibile verificare la chiave DeepL. Stato: [STATUS]. Verifica la chiave e riprova.</string>
<string name="azure_api_key_verified">ID di Azure verificato.</string>
<string name="google_api_key_verified">Chiave API di Google verificata.</string>
<string name="deepl_api_key_verified">Chiave di DeepL verificata.</string>

View File

@ -55,6 +55,8 @@
</combo_box>
<search_editor label="Regioni per nome" name="location" tool_tip="Digita il nome di una regione"/>
<button label="Cerca" name="DoSearch" tool_tip="Cerca la regione sulla mappa"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Posizione:
</text>

View File

@ -479,6 +479,8 @@
<name_list name="AccessList" tool_tip="(最大[MAX]人中[LISTED]人が登録されています。)"/>
<button label="追加" name="add_allowed"/>
<button label="削除" label_selected="削除" name="remove_allowed"/>
<button label="エクスポート" label_selected="エクスポート" name="export_allowed"/>
<button tool_tip="有効なUUIDのみ(1行に1つ、余分な文字やフォーマットなし)を含むCSV形式のファイルをインポートします。" label="インポート" label_selected="インポート" name="import_allowed"/>
</panel>
<panel name="Banned_layout_panel">
<text label="バン" name="BanCheck">
@ -490,6 +492,8 @@
</name_list>
<button label="追加" name="add_banned"/>
<button label="削除" label_selected="削除" name="remove_banned"/>
<button label="エクスポート" label_selected="エクスポート" name="export_banned"/>
<button tool_tip="有効なUUIDのみ(1行に1つ、余分な文字やフォーマットなし)を含むCSV形式のファイルをインポートします。" label="インポート" label_selected="インポート" name="import_banned"/>
</panel>
</panel>
<panel label="体験" name="land_experiences_panel"/>

View File

@ -256,11 +256,12 @@
トラックパッドの感度:
</text>
<slider name="trackpad_sensitivity_slider" tool_tip="トラックボールの感度を調整します。"/>
<check_box name="natural_direction_checkbox" label="自然な配置を使用する" tool_tip="デフォルトでは、スケルトンの関節の回転は不自然です。これにより、ポーズが複雑になります。チェックすると、関節がより自然に回転します。"/>
<check_box name="stop_posing_on_close_checkbox" label="閉じたらポーズを止める" tool_tip="ポーズを止めないことは、多くの作業を行っていて、誤ってポーズを失いたくない場合に役に立ちます。"/>
<check_box name="reset_base_rotation_on_edit_checkbox" label="編集時にベース回転をリセット" tool_tip="回転を初めて編集するときは、ゼロにリセットします。これにより、作業でポーズを保存できます。(差分ではなく、読み込み/保存を参照)ゼロにエクスポートした各ジョイントの横に緑色のチェックマークが表示されます。"/>
<check_box name="also_save_bvh_checkbox" label="保存時にBVHを書き込む**" tool_tip="ポーズを保存するときに、BVHファイルも作成します。このファイルは、「ビルド」>「アップロード」>「アニメーション」からアップロードして、自分自身または他のユーザーにインワールドのポーズを与えることができます。BVHにはオリジナルの作業が必要なので、ジョイントの「ベース」をゼロにリセットする必要があります。"/>
<check_box name="confirm_overwrite_on_save_checkbox" label="上書きを確認" tool_tip="ポーズを保存するときに、ファイルがすでに存在する場合は、上書きすることを確認するために、もう一度保存ボタンをクリックする必要があります。"/>
<check_box name="natural_direction_checkbox" label="自然な配置を使用する" tool_tip="デフォルトでは、スケルトンの関節の回転は不自然です。これにより、ポーズが複雑になります。チェックすると、関節がより自然に回転します。"/>
<check_box name="show_joint_markers_checkbox" label="ジョイント部にマーカーを表示" tool_tip="視覚的なポージングにジョイント部の選択を支援するための小さなインジケーターを表示します。"/>
</panel>
</tab_container>
<button name="toggleVisualManipulators" tool_tip="視覚マニピュレータのオン/オフを切り替えます。"/>

View File

@ -50,7 +50,8 @@
</combo_box>
<search_editor label="リージョン名で" name="location" tool_tip="リージョン名を入力してください。"/>
<button label="探す" name="DoSearch" tool_tip="リージョンを検索します。"/>
<button name="Clear" tool_tip="追跡ラインをクリアしてマップをリセットします。"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
場所:
</text>

View File

@ -208,7 +208,7 @@
<text name="preferences_search_bg_label">
背景:
</text>
<color_swatch name="preferences_search_color" tool_tip="初期設定の検索結果のハイライトの背景色を選択します。"/>
<color_swatch name="preferences_search_bg_color" tool_tip="初期設定の検索結果のハイライトの背景色を選択します。"/>
<text name="preferences_search_font_label">
フォント:
</text>

View File

@ -13,6 +13,8 @@
<!-- Estate Managers buttons -->
<button label="追加…" name="add_estate_manager_btn"/>
<button label="削除…" name="remove_estate_manager_btn"/>
<button label="エクスポート…" name="export_estate_manager_btn"/>
<button tool_tip="有効なUUIDのみ(1行に1つ、余分な文字やフォーマットなし)を含むCSV形式のファイルをインポートします。" label="インポート…" name="import_estate_manager_btn"/>
</panel>
<!-- ================================ ALLOWED tab =========================== -->
<panel label="許可" name="allowed_panel">
@ -30,6 +32,8 @@
<!-- Always allowed buttons -->
<button label="追加…" name="add_allowed_avatar_btn"/>
<button label="削除…" name="remove_allowed_avatar_btn"/>
<button label="エクスポート…" name="export_allowed_list_btn"/>
<button tool_tip="有効なUUIDのみ(1行に1つ、余分な文字やフォーマットなし)を含むCSV形式のファイルをインポートします。" label="インポート…" name="import_allowed_list_btn"/>
</panel>
<!-- ============================= ALLOWED GROUPS tab ======================= -->
<panel label="許可するグループ" name="allowed_groups_panel">
@ -47,6 +51,8 @@
<!-- Groups always allowed buttons -->
<button label="追加…" name="add_allowed_group_btn"/>
<button label="削除…" name="remove_allowed_group_btn"/>
<button label="エクスポート…" name="export_allowed_group_btn"/>
<button tool_tip="有効なUUIDのみ(1行に1つ、余分な文字やフォーマットなし)を含むCSV形式のファイルをインポートします。" label="インポート…" name="import_allowed_group_btn"/>
</panel>
<!-- ================================ BANNED tab ============================ -->
<panel label="バン" name="banned_panel">
@ -67,6 +73,8 @@
<!-- Always banned buttons -->
<button label="追加…" name="add_banned_avatar_btn"/>
<button label="削除…" name="remove_banned_avatar_btn"/>
<button label="エクスポート…" name="export_banned_avatar_btn"/>
<button tool_tip="有効なUUIDのみ(1行に1つ、余分な文字やフォーマットなし)を含むCSV形式のファイルをインポートします。" label="インポート…" name="import_banned_avatar_btn"/>
</panel>
</tab_container>
</panel>

View File

@ -6590,4 +6590,9 @@ Rez時間[OBJECT_REZ_TIME]
<string name="FSObjectInventoryElements">[NUM_ELEMENTS]件の要素</string>
<string name="OpenSimInventoryValidationErrorGenericHelp">グリッドオペレータのサポートチーム</string>
<string name="Unlimited">無制限</string>
</strings>
<string name="ListEmpty">リストは空です。</string>
<string name="NoValidUUIDs">インポートされたファイル内に有効なUUIDが見つかりません。</string>
<string name="ImportListTooLarge">エントリが多すぎます。CSVファイルには[COUNT]個のエントリがあり、残り使用可能なスロット数は[MAX]個です。</string>
<string name="ImportSuccessful">[COUNT]件のエントリを正常に処理しました。</string>
</strings>

View File

@ -439,6 +439,8 @@ teksturę:
<name_list name="AccessList" tool_tip="([LISTED] na liście, [MAX] maksimum)"/>
<button label="Dodaj" name="add_allowed"/>
<button label="Usuń" label_selected="Usuń" name="remove_allowed"/>
<button label="Eksport" label_selected="Eksport" name="export_allowed"/>
<button label="Import" label_selected="Import" tool_tip="Zaimportuj plik CSV zawierający tylko prawidłowe identyfikatory UUID - po jednym w każdym wierszu, bez dodatkowych znaków i formatowania." name="import_allowed"/>
</panel>
<panel name="Banned_layout_panel">
<text label="Banuj" name="BanCheck">
@ -450,6 +452,8 @@ teksturę:
</name_list>
<button label="Dodaj" name="add_banned"/>
<button label="Usuń" label_selected="Usuń" name="remove_banned"/>
<button label="Eksport" label_selected="Eksport" name="export_banned"/>
<button label="Import" label_selected="Import" tool_tip="Zaimportuj plik CSV zawierający tylko prawidłowe identyfikatory UUID - po jednym w każdym wierszu, bez dodatkowych znaków i formatowania." name="import_banned"/>
</panel>
</panel>
<panel label="Przygody" name="land_experiences_panel"/>

View File

@ -244,11 +244,12 @@
<panel title="Inne" name="settings_panel">
<text name="trackpad_sensitivity_label">Czułość trackpada:</text>
<slider name="trackpad_sensitivity_slider" tool_tip="Dostosowuje czułość trackballa / kółka" />
<check_box name="natural_direction_checkbox" label="Naturalne wyrównanie" tool_tip="Szkielet ma domyślnie nienaturalne rotacje stawów. To utrudnia pozowanie. Po zaznaczeniu stawy będą się obracać w bardziej naturalny sposób." />
<check_box name="stop_posing_on_close_checkbox" label="Stop pozy po zamknięciu" tool_tip="Brak zatrzymywania pozy może być pomocny, jeśli nie chcesz jej przypadkowo stracić." />
<check_box name="reset_base_rotation_on_edit_checkbox" label="Reset bazy rotacji na edycji" tool_tip="Gdy po raz pierwszy edytujesz obrót, zresetuj go do zera. Oznacza to, że Twoja praca może zapisać pozę (a nie różnicę, patrz ładowanie / zapisywanie). Zielony 'ptaszek' pojawia się obok każdego wyzerowanego tak, wyeksportowanego stawu." />
<check_box name="also_save_bvh_checkbox" label="Twórz BVH podczas zapisu**" tool_tip="Podczas zapisywania pozy twórz również plik BVH, który można przesłać za pomocą 'Buduj > Prześlij > Animację', aby móc ustawiać siebie lub innych w świecie. Należy zresetować 'bazę' stawów do zera, ponieważ BVH wymaga oryginalnej pracy." />
<check_box name="confirm_overwrite_on_save_checkbox" label="Potwierdź nadpisanie" tool_tip="Gdy zapisujesz pozę, a plik już istnieje, musisz kliknąć przycisk zapisu ponownie, aby potwierdzić, że na pewno chcesz ją nadpisać." />
<check_box name="natural_direction_checkbox" label="Naturalne wyrównanie" tool_tip="Szkielet ma domyślnie nienaturalne rotacje stawów. To utrudnia pozowanie. Po zaznaczeniu stawy będą się obracać w bardziej naturalny sposób." />
<check_box name="show_joint_markers_checkbox" label="Wskaźniki stawów" tool_tip="Pokaż małe wskaźniki ułatwiające wybór stawów podczas pozowania." />
</panel>
</tab_container>
<button name="toggleVisualManipulators" tool_tip="Włącz / wyłącz manipulatory wizualne." />

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater name="floater_translation_settings" title="Ustawienia tłumaczenia czatu">
<string name="azure_api_key_not_verified">Nie można zweryfikować ID usługi Azure. Spróbuj ponownie.</string>
<string name="google_api_key_not_verified">Nie można zweryfikować klucza Google API. Spróbuj ponownie.</string>
<string name="deepl_api_key_not_verified">Nie można zweryfikować klucza DeepL. Status: [STATUS]. Spróbuj ponownie.</string>
<string name="azure_api_key_not_verified">Nie można zweryfikować ID usługi Azure. Status: [STATUS]. Sprawdź ustawienia i spróbuj ponownie.</string>
<string name="google_api_key_not_verified">Nie można zweryfikować klucza Google API. Status: [STATUS]. Sprawdź klucz i spróbuj ponownie.</string>
<string name="deepl_api_key_not_verified">Nie można zweryfikować klucza DeepL. Status: [STATUS]. Sprawdź klucz i spróbuj ponownie.</string>
<string name="azure_api_key_verified">ID usługi Azure zweryfikowany.</string>
<string name="google_api_key_verified">Klucz Google API zweryfikowany.</string>
<string name="deepl_api_key_verified">Klucz DeepL zweryfikowany.</string>

View File

@ -49,6 +49,8 @@
</combo_box>
<search_editor label="Regiony według nazwy" name="location" tool_tip="Wpisz nazwę regionu"/>
<button label="Znajdź" name="DoSearch" tool_tip="Szukaj regionu"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Lokalizacja:
</text>

View File

@ -15,6 +15,10 @@
<check_box label="Prowadnice" tool_tip="Pokaż prowadnicę kadrowania (zasadę trójpodziału) wewnątrz ramki migawki." name="show_guides" />
<button label="Odśwież" name="new_snapshot_btn" tool_tip="Kliknij, aby odświeżyć" />
<button label="Podgląd" name="big_preview_btn" tool_tip="Kliknij, aby przełączyć podgląd" />
<text name="store_label">
Ślij jako:
</text>
<combo_box name="stores_combobox" tool_tip="Jeśli masz jeden lub więcej sklepów Easy Blogger przypisanych do Primfeed, to pojawią się one tutaj." />
<text name="description_label">
Opis:
</text>

View File

@ -9,7 +9,9 @@
<columns label="Imię" name="name" />
</name_list>
<button label="Dodaj..." name="add_estate_manager_btn" />
<button label="Usuń..." name="remove_estate_manager_btn" />
<button label="Usuń..." name="remove_estate_manager_btn" />
<button label="Eksportuj..." name="export_estate_manager_btn" />
<button label="Importuj..." name="import_estate_manager_btn" tool_tip="Zaimportuj plik CSV zawierający tylko prawidłowe identyfikatory UUID - po jednym w każdym wierszu, bez dodatkowych znaków i formatowania." />
</panel>
<panel label="Dozwoleni" name="allowed_panel">
<panel name="allowed_search_panel">
@ -24,6 +26,8 @@
</name_list>
<button label="Dodaj..." name="add_allowed_avatar_btn" />
<button label="Usuń..." name="remove_allowed_avatar_btn" />
<button label="Eksportuj..." name="export_allowed_list_btn" />
<button label="Importuj..." name="import_allowed_list_btn" tool_tip="Zaimportuj plik CSV zawierający tylko prawidłowe identyfikatory UUID - po jednym w każdym wierszu, bez dodatkowych znaków i formatowania." />
</panel>
<panel label="Dozwolone grupy" name="allowed_groups_panel">
<panel name="allowed_group_search_panel">
@ -38,6 +42,8 @@
</name_list>
<button label="Dodaj..." name="add_allowed_group_btn" />
<button label="Usuń..." name="remove_allowed_group_btn" />
<button label="Eksportuj..." name="export_allowed_group_btn" />
<button label="Importuj..." name="import_allowed_group_btn" tool_tip="Zaimportuj plik CSV zawierający tylko prawidłowe identyfikatory UUID - po jednym w każdym wierszu, bez dodatkowych znaków i formatowania." />
</panel>
<panel label="Zbanowani" name="banned_panel">
<panel name="banned_search_panel">
@ -55,6 +61,8 @@
</name_list>
<button label="Dodaj..." name="add_banned_avatar_btn" />
<button label="Usuń..." name="remove_banned_avatar_btn" />
<button label="Eksportuj..." name="export_banned_avatar_btn" />
<button label="Importuj..." name="import_banned_avatar_btn" tool_tip="Zaimportuj plik CSV zawierający tylko prawidłowe identyfikatory UUID - po jednym w każdym wierszu, bez dodatkowych znaków i formatowania." />
</panel>
</tab_container>
</panel>

View File

@ -6646,4 +6646,16 @@ Twoja aktualna pozycja: [AVATAR_POS]
<string name="Unlimited">
Bez ograniczeń
</string>
<string name="ListEmpty">
Lista jest pusta
</string>
<string name="NoValidUUIDs">
Nie znaleziono prawidłowych identyfikatorów UUID w importowanym pliku.
</string>
<string name="ImportListTooLarge">
Zbyt wiele rekordów. Plik CSV ma [COUNT] rekordów, ale jest dostępnych [MAX] slotów.
</string>
<string name="ImportSuccessful">
Pomyślnie przetworzono [COUNT] rekordów.
</string>
</strings>

View File

@ -65,6 +65,8 @@
<search_editor label="Regiões por nome" name="location" tool_tip="Digite o nome da região"/>
<button label="Buscar" name="DoSearch" tool_tip="Buscar região"/>
<button name="Clear" tool_tip="Limpar linhas e redefinir mapa"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Local:
</text>

View File

@ -467,6 +467,7 @@
<name_list name="AccessList" tool_tip="([LISTED] в списке, [MAX] максимум)" />
<button label="Добавить" name="add_allowed" />
<button label="Удалить" label_selected="Удалить" name="remove_allowed" />
<button label="Экспорт" label_selected="Экспорт" name="export_allowed" />
</panel>
<panel name="Banned_layout_panel">
<text name="BanCheck">
@ -477,7 +478,8 @@
<columns label="Время" name="duration"/>
</name_list>
<button label="Добавить" name="add_banned"/>
<button label="Удалить" label_selected="Удалить" name="remove_banned" />
<button label="Удалить" label_selected="Удалить" name="remove_banned" />
<button label="Экспорт" label_selected="Экспорт" name="export_banned" />
</panel>
</panel>
<panel label="Приключения" name="land_experiences_panel"/>

View File

@ -59,20 +59,17 @@
</combo_box>
<search_editor label="Название региона" name="location" tool_tip="Введите название региона"/>
<button label="Поиск" name="DoSearch" tool_tip="Поиск региона"/>
<button label="Очистить" name="Clear" tool_tip="Очистить отслеживание и сбросить карту до стандартного вида"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Место:
</text>
<button label="Телепорт" name="Teleport" tool_tip="Телепортация в выбранное место"/>
<button label="Копировать" name="copy_slurl" tool_tip="Копировать текущее место в виде URL-адреса SL для использования в интернете."/>
<button label="Очистить" name="Clear" tool_tip="Очистить отслеживание и сбросить карту до стандартного вида"/>
<button label="Показать место" name="Show Destination" tool_tip="Центрировать карту на выбранном месте"/>
<button label="Отследить регион" name="track_region" tool_tip="Добавить регион в отслеживание"/>
</panel>
<panel name="layout_panel_5">
<text name="zoom_label">
Увеличение
</text>
</panel>
</layout_panel>
</layout_stack>
</floater>

View File

@ -10,6 +10,7 @@
</name_list>
<button label="Добавить..." name="add_estate_manager_btn"/>
<button label="Удалить..." name="remove_estate_manager_btn"/>
<button label="Экспорт..." name="export_estate_manager_btn"/>
</panel>
<panel label="Разрешенные" name="allowed_panel">
<panel label="top_panel" name="allowed_search_panel">
@ -24,6 +25,7 @@
</name_list>
<button label="Добавить..." name="add_allowed_avatar_btn"/>
<button label="Удалить..." name="remove_allowed_avatar_btn"/>
<button label="Экспорт..." name="export_allowed_list_btn"/>
</panel>
<panel label="Допущенные Группы" name="allowed_groups_panel">
<panel label="top_panel" name="allowed_group_search_panel">
@ -38,6 +40,7 @@
</name_list>
<button label="Добавить..." name="add_allowed_group_btn"/>
<button label="Удалить..." name="remove_allowed_group_btn"/>
<button label="Экспорт..." name="export_allowed_group_btn"/>
</panel>
<panel label="Заблокированы" name="banned_panel">
<panel label="top_panel" name="banned_search_panel">
@ -55,6 +58,7 @@
</name_list>
<button label="Добавить..." name="add_banned_avatar_btn"/>
<button label="Удалить..." name="remove_banned_avatar_btn"/>
<button label="Экспорт..." name="export_banned_avatar_btn"/>
</panel>
</tab_container>
</panel>

View File

@ -6876,5 +6876,6 @@ ID объекта: [INSPECTING_KEY]
<string name="FSObjectInventoryOneElement">1 элемент</string>
<string name="FSObjectInventoryElements">[NUM_ELEMENTS] элементов</string>
<string name="OpenSimInventoryValidationErrorGenericHelp">команда поддержки оператора вашей сетки</string>
<string name="Unlimited">Неограниченный</string>
<string name="Unlimited">Неограниченный</string>
<string name="ListEmpty">Список пуст</string>
</strings>

View File

@ -57,17 +57,14 @@
</combo_box>
<search_editor label="Adlarına Göre Bölgeler" name="location" tool_tip="Bir bölgenin adını yazın"/>
<button label="Bul" name="DoSearch" tool_tip="Bölge ara"/>
<button name="Clear" tool_tip="Takip çizgilerini temizle ve haritayı sıfırla"/>
</panel>
<panel name="layout_panel_7">
<text name="events_label">
Konum:
</text>
<button label="Işınla" name="Teleport" tool_tip="Seçilen konuma ışınla"/>
<button label="SLurl&apos;i Kopyala" name="copy_slurl" tool_tip="Mevcut konumu, web üzerinde kullanılması için SLurl olarak kopyalar."/>
<button name="Clear" tool_tip="Takip çizgilerini temizle ve haritayı sıfırla"/>
<button label="Seçimi Göster" name="Show Destination" tool_tip="Haritanın merkezi seçilen konum olsun"/>
</panel>
<panel name="layout_panel_5">
<text name="zoom_label">
Yakınlaştır
</text>
</panel>
</floater>

View File

@ -495,6 +495,8 @@
<name_list name="AccessList" tool_tip="(已加入 [LISTED],最多可加 [MAX]" />
<button label="新增" name="add_allowed" />
<button label="移除" label_selected="移除" name="remove_allowed" />
<button label="匯出" label_selected="匯出" name="export_allowed"/>
<button label="匯入" label_selected="匯入" name="import_allowed" tool_tip="只匯入包含有效UUID的CSV檔案——每行一個無多餘字元或格式"/>
</panel>
<panel name="Banned_layout_panel">
<text label="禁止" name="BanCheck">
@ -506,6 +508,8 @@
</name_list>
<button label="新增" name="add_banned" />
<button label="移除" label_selected="移除" name="remove_banned" />
<button label="匯出" label_selected="匯出" name="export_banned"/>
<button label="匯入" label_selected="匯入" name="import_banned" tool_tip="只匯入包含有效UUID的CSV檔案——每行一個無多餘字元或格式"/>
</panel>
</panel>
<panel label="體驗" name="land_experiences_panel" />

View File

@ -62,7 +62,7 @@
<check_box name="filter_perm_copy" label="可複製" />
<check_box name="filter_perm_modify" label="可修改" />
<check_box name="filter_perm_transfer" label="可轉讓" />
<check_box name="filter_reflection_probe" label="反射探針" tool_tip="僅包含手動探針,不包括自動探針。僅在顯示設置中啟用鏡面時才包含鏡面探針。如果反射範圍設置為“無”或者探針未烘焙,則可能無法識別物件。"/>
<check_box name="filter_reflection_probe" label="反射探針" tool_tip="僅包含手動探針,不包括自動探針。僅在顯示設置中啟用鏡面時才包含鏡面探針。如果反射範圍設置為「無」或者探針未烘焙,則可能無法識別物件。"/>
<check_box name="filter_for_sale" label="出售價格介於" />
<text name="and">

View File

@ -18,12 +18,12 @@
</text>
<color_swatch label="顏色" name="global_swatch" tool_tip="點擊以打開顏色選擇" />
<text name="label_online">
通知:
線通知:
</text>
<check_box label="將所有好友的通知顯示在彈出視窗中" name="ChatOnlineNotification" />
<check_box label="將所有好友的通知顯示在聊天中" name="OnlineOfflinetoNearbyChat" />
<check_box label="將特定分組的通知顯示為彈出視窗中" name="FSContactSetsNotificationToast" />
<check_box label="將特定分組的通知顯示在聊天中" name="FSContactSetsNotificationNearbyChat" />
<check_box label="將所有好友的線通知顯示在彈出視窗中" name="ChatOnlineNotification" />
<check_box label="將所有好友的線通知顯示在聊天中" name="OnlineOfflinetoNearbyChat" />
<check_box label="將特定分組的線通知顯示為彈出視窗中" name="FSContactSetsNotificationToast" />
<check_box label="將特定分組的線通知顯示在聊天中" name="FSContactSetsNotificationNearbyChat" />
<text name="label_colors">
自訂顏色:
</text>

View File

@ -246,11 +246,12 @@
觸控板敏感度:
</text>
<slider name="trackpad_sensitivity_slider" tool_tip="設定觸控板的敏感度"/>
<check_box name="natural_direction_checkbox" label="使用自然對齊" tool_tip="骨骼預設具有不自然的關節旋轉,這可能會讓姿勢調整變得更複雜。選取此選項後,關節將以更自然的方式旋轉。" />
<check_box name="stop_posing_on_close_checkbox" label="關閉時停止" tool_tip="關閉時不停止姿勢可有助於保留目前工作。"/>
<check_box name="reset_base_rotation_on_edit_checkbox" label="編輯時重設基礎旋轉" tool_tip="首次編輯旋轉時,將其重設為零。這意味著可以保存完整的姿勢(而不僅僅是差異,請參閱載入/保存)。每個以零為基準匯出的關節旁都會顯示綠色勾選標誌。" />
<check_box name="also_save_bvh_checkbox" label="儲存時也儲存BHV" tool_tip="當姿勢被儲存時將同時創建一個BHV檔案該檔案可以透過建造 > 上傳 > 動畫上傳並用於自己或其他化身的姿勢。為了實現此功能關節的基礎位置必須設為零因為BHV無法從其他姿勢推導出來。"/>
<check_box name="confirm_overwrite_on_save_checkbox" label="確認覆蓋" tool_tip="儲存姿勢時,如果檔案已存在,您需要再次點擊保存按鈕以確認覆蓋。" />
<check_box name="reset_base_rotation_on_edit_checkbox" label="編輯時重設基礎旋轉" tool_tip="首次編輯旋轉時,將其重設為零。這意味著可以保存完整的姿勢(而不僅僅是差異,請參閱載入/保存)。每個以零為基準匯出的關節旁都會顯示綠色勾選標誌。" />
<check_box name="natural_direction_checkbox" label="使用自然對齊" tool_tip="骨骼預設具有不自然的關節旋轉,這可能會讓姿勢調整變得更複雜。選取此選項後,關節將以更自然的方式旋轉。" />
<check_box name="show_joint_markers_checkbox" label="顯示關節標記" tool_tip="顯示關節標記,以便在姿勢編輯時更輕鬆地選擇關節。" />
</panel>
</tab_container>
<button name="toggleVisualManipulators" tool_tip="啟用 / 停用可視操控器。" />

View File

@ -107,9 +107,10 @@
</string>
<string name="IncompleteTC">
紋理座標數據不完整。
</string>
<string name="PositionNaN">
在從DAE模型載入位置資料時發現NaN模型無效。
</string></string>
</string>
<string name="NormalsNaN">
載入DAE模型時發現法線NaN模型無效。
</string>

View File

@ -52,7 +52,7 @@
<check_box label="启用反射探針选择" name="checkbox select probes" tool_tip="启用后可在场景中选择并检查反射探針。"/>
</panel>
<panel name="P_R_Res_2">
<text name="ReflectionDetailText" tool_tip="决定反射细节级别。“仅静态”仅反射静止物件,更高设置包含动态物件和实时反射。">
<text name="ReflectionDetailText" tool_tip="决定反射细节级别。「仅静态」仅反射静止物件,更高设置包含动态物件和实时反射。">
反射细节
</text>
<combo_box name="ReflectionDetail">
@ -60,7 +60,7 @@
<combo_box.item label="静态+动态" name="1"/>
<combo_box.item label="实时" name="2"/>
</combo_box>
<text name="ReflectionProbeText" tool_tip="控制场景反射覆盖范围。“仅手动”反射选定物件,“全场景”包含视野内所有内容。">
<text name="ReflectionProbeText" tool_tip="控制场景反射覆盖范围。「仅手动」反射选定物件,「全场景」包含视野内所有内容。">
反射覆盖
</text>
<combo_box name="ReflectionLevel">
@ -300,7 +300,7 @@
最大化身數
</text>
<button name="Reset_Avi_Count" tool_tip="重設為預設值。" />
<text name="T_Avi_Detail" tool_tip="調整化身的細節層次等級LOD。較高的值提高視覺質量使舊版化身在較遠距離也顯得更為詳細。較低的值減少細節以提高效能這在高密度區域或低端系統上非常有用。此設置主要影響舊版系統化身。網格化身受此設置的影響較小因為它們的細節層次級別由其自身的細節層次設置控制並進一步受“偏好設置”裡“顯示” → ”化身複雜度”設置影響。">
<text name="T_Avi_Detail" tool_tip="調整化身的細節層次等級LOD。較高的值提高視覺質量使舊版化身在較遠距離也顯得更為詳細。較低的值減少細節以提高效能這在高密度區域或低端系統上非常有用。此設置主要影響舊版系統化身。網格化身受此設置的影響較小因為它們的細節層次級別由其自身的細節層次設置控制並進一步受「偏好設置」裡「顯示」 → 」化身複雜度」設置影響。">
化身細節
</text>
<button name="Reset_Avi_Detail" tool_tip="重設為預設值。" />
@ -387,7 +387,7 @@
<combo_box.item label="1024像素" name="1024"/>
<combo_box.item label="2048像素" name="2048"/>
</combo_box>
<text name="T_AvatarDisplay" tool_tip="根據複雜度和好友狀態控制化身的顯示方式。“按複雜度限制”限制彩現超過一定複雜度的化身以提高性能。“始終顯示好友”確保好友無論多複雜都能完全彩現。“僅顯示好友”僅彩現您的好友,隱藏其他化身,以在擁擠區域優化性能。">
<text name="T_AvatarDisplay" tool_tip="根據複雜度和好友狀態控制化身的顯示方式。「按複雜度限制」限制彩現超過一定複雜度的化身以提高性能。「始終顯示好友」確保好友無論多複雜都能完全彩現。「僅顯示好友」僅彩現您的好友,隱藏其他化身,以在擁擠區域優化性能。">
化身顯示
</text>
<combo_box name="AvatarComplexityModeSelection">
@ -420,7 +420,7 @@
<button name="Debug Settings" label="顯示調試設置" tool_tip="打開調試設置菜單,允許訪問標準首選項中不可用的高級檢視器設置。請謹慎使用,因為更改可能會影響性能和穩定性。"/>
</panel>
<panel name="P_Quick_Stats">
<text name="T_Quick_Stats" tool_tip="显示实时系统性能统计,帮助您评估檢視器的效率。您可以通过点击标签来展开或折叠各指标。">
<text name="T_Quick_Stats" tool_tip="显示实时系统性能统计,帮助您评估檢視器的效率。您可以通过点击标签来展开或折叠各指标。">
統計資訊
</text>
</panel>
@ -465,11 +465,11 @@
旋轉
</text>
<button name="Reset_Spin" tool_tip="重設為預設值。" />
<text name="T_Roll" tool_tip="調整相機左右滾動的靈敏度,這會使相機側向傾斜,類似於將頭左右旋轉。較低的值提供更精細的控制以進行精確調整,而較高的值使滾動更為靈敏。注意:如果啟用了“自動水平校正”,此設置將不起作用,因為自動水平校正會保持相機水平,防止任何滾動移動。">
<text name="T_Roll" tool_tip="調整相機左右滾動的靈敏度,這會使相機側向傾斜,類似於將頭左右旋轉。較低的值提供更精細的控制以進行精確調整,而較高的值使滾動更為靈敏。注意:如果啟用了「自動水平校正」,此設置將不起作用,因為自動水平校正會保持相機水平,防止任何滾動移動。">
滾動
</text>
<button name="Reset_Roll" tool_tip="重設為預設值。" />
<text name="T_Zoom_Speed" tool_tip="通過調整相機的焦距或垂直視場來控制變焦方式,類似於更換真實相機的鏡頭。這會影響場景的可見範圍以及視圖的“變焦”效果。要激活變焦功能將變焦軸映射設置為“4”。此設置不影響變焦的平滑度,而是決定視場調整的範圍,從而對相機的變焦級別進行精確控制。">
<text name="T_Zoom_Speed" tool_tip="通過調整相機的焦距或垂直視場來控制變焦方式,類似於更換真實相機的鏡頭。這會影響場景的可見範圍以及視圖的「變焦」效果。要激活變焦功能將變焦軸映射設置為「4」。此設置不影響變焦的平滑度,而是決定視場調整的範圍,從而對相機的變焦級別進行精確控制。">
縮放
</text>
<button name="Reset_Zoom_Speed" tool_tip="重設為預設值。" />
@ -479,9 +479,9 @@
<button name="Reset_Feathering" tool_tip="重設為預設值。" />
</panel>
<panel name="P_Axis_Mapping">
<spinner label="縮放軸對映" name="JoystickAxis6" tool_tip="確定哪個操縱桿或滑鼠軸控制變焦功能。將其設置為“4”以通過操縱桿啟用變焦。"/>
<spinner label="縮放軸對映" name="JoystickAxis6" tool_tip="確定哪個操縱桿或滑鼠軸控制變焦功能。將其設置為「4」以通過操縱桿啟用變焦。"/>
<check_box label="啟用3D滑鼠" tool_tip="啟用或禁用用於控制相機的操縱桿/3D滑鼠支持。" name="enable_joystick" />
<check_box name="CB_ZoomDirect" label="啟用縮放控制(見工具提示!)" tool_tip="使用3D滑鼠激活變焦控制。確保“變焦軸對映”設置為“4”以確保正常功能。"/>
<check_box name="CB_ZoomDirect" label="啟用縮放控制(見工具提示!)" tool_tip="使用3D滑鼠激活變焦控制。確保「變焦軸對映」設置為「4」以確保正常功能。"/>
<check_box name="CB_AutoLeveling" label="自動校準(無相機捲動)" tool_tip="保持相機水平,防止意外的滾動。這對於在移動時保持穩定的地平線很有用。"/>
<check_box name="CB_Move_Avatar" label="使用3D滑鼠控制化身" tool_tip="允許3D滑鼠控制化身移動而不僅是相機。"/>
<check_box name="CB_Move_Objects" label="使用3D滑鼠移動物件" tool_tip="啟用3D滑鼠在建造和編輯期間進行物件操作。"/>

View File

@ -16,7 +16,7 @@
<text name="MaxTextureResolutionLabel">
最大細節層次解析度:
</text>
<combo_box name="MaxTextureResolution" tool_tip="“細節層次(LOD)”紋理的最大解析度"/>
<combo_box name="MaxTextureResolution" tool_tip="「細節層次(LOD)」紋理的最大解析度"/>
<check_box label="啟用垂直同步" tool_tip="將影格速率與顯示器的更新率同步,可能會導致更多的卡頓和輸入延遲。" name="vsync" />
<text name="AvatarText">
化身
@ -136,6 +136,7 @@
<combo_box.item label="少量" name="32" />
<combo_box.item label="中等" name="64" />
<combo_box.item label="很多" name="128" />
<combo_box.item label="超多" name="256" />
</combo_box>
<slider label="曝光度:" name="RenderExposure" />
<check_box label="鏡面" name="Mirrors" />
@ -160,7 +161,6 @@
<combo_box.item label="ACES" name="1"/>
</combo_box>
<slider label="色調映射混合:" tool_tip="在線性與色調映射顏色之間進行混合" name="TonemapMix"/>
<!-- End of mirror settings -->
<button label="重設為我們建議的設定" name="Defaults" />
<button label="確定" label_selected="確定" name="OK" />
<button label="取消" label_selected="取消" name="Cancel" />

View File

@ -2,7 +2,7 @@
<floater name="profile_permissions">
<string name="description_string" value="[AGENT_NAME]的權限:" />
<text name="perm_description" value="允許居民:" />
<check_box name="online_check" label="時可見" />
<check_box name="online_check" label="線時可見" />
<check_box name="map_check" label="在世界地圖上找到我" />
<check_box name="objects_check" label="編輯、刪除或拿走我的物件" />
<button name="perms_btn_ok" label="確定" />

View File

@ -53,14 +53,16 @@
</text>
</panel>
<panel name="layout_panel_4">
<combo_box label="的朋友" name="friend combo" tool_tip="顯示朋友在地圖上">
<combo_box.item label="我的朋友" name="item1" />
<combo_box label="線的朋友" name="friend combo" tool_tip="顯示朋友在地圖上">
<combo_box.item label="我線的朋友" name="item1" />
</combo_box>
<combo_box label="我的地標" name="landmark combo" tool_tip="將地標位置顯示在地圖上">
<combo_box.item label="我的地標" name="item1" />
</combo_box>
<search_editor label="按區域名稱" name="location" tool_tip="輸入一個區域的名稱" />
<button label="尋找" name="DoSearch" tool_tip="搜尋區域" />
</panel>
<panel name="layout_panel_7">
<text name="events_label">
位置:
</text>

View File

@ -24,5 +24,5 @@
<menu_item_check label="完整名稱格式:顯示名 (使用者名稱)" name="format_displayname_username" />
<menu_item_check label="搜尋過濾器" name="friend_filter" />
</menu>
<menu_item_check label="對朋友顯示狀態" name="GlobalOnlineStatusToggle" />
<menu_item_check label="對朋友顯示線狀態" name="GlobalOnlineStatusToggle" />
</context_menu>

View File

@ -15,5 +15,5 @@
<menu_item_check label="完整名稱格式:顯示名 (使用者名稱)" name="format_displayname_username" />
<menu_item_check label="搜尋過濾器" name="friend_filter" />
</menu>
<menu_item_check label="對朋友顯示狀態" name="GlobalOnlineStatusToggle" />
<menu_item_check label="對朋友顯示線狀態" name="GlobalOnlineStatusToggle" />
</context_menu>

View File

@ -30,7 +30,7 @@
<menu_item_call label="複製 SLurl" name="url_copy" />
<menu_item_call label="新增地標" name="About Landmark" />
<menu_item_call label="顯示在地圖上" name="show_on_map" />
<menu_item_call label="播放" name="Animation Play" />
<menu_item_call label="線播放" name="Animation Play" />
<menu_item_call label="本地播放" name="Animation Audition" />
<menu_item_call label="傳送私聊" name="Send Instant Message" />
<menu_item_call label="傳送瞬間傳送邀請..." name="Offer Teleport..." />

View File

@ -77,7 +77,7 @@
<menu_item_call label="退出 [APP_NAME]" name="Quit" />
</menu>
<menu label="通訊" name="Communicate">
<menu label="狀態" name="Status">
<menu label="線狀態" name="Status">
<menu_item_check label="離開" name="Away" />
<menu_item_check label="請勿打擾" name="Do Not Disturb" />
<menu_item_check label="自動回復" name="Set Autorespond" />

View File

@ -1292,7 +1292,7 @@
你沒有權限為你當前的群組購買土地。
</notification>
<notification label="加為朋友" name="AddFriendWithMessage">
朋友可以允許彼此在地圖上追蹤對方,並接收彼此的線狀態更新訊息。
朋友可以允許彼此在地圖上追蹤對方,並接收彼此的線狀態更新訊息。
向 [NAME] 發出交友邀請?
<form name="form">
@ -1926,7 +1926,7 @@ URL:[UNTRUSTED_URL]
<notification name="AutorespondModeSet">
自動回覆已開啟。
發件人發送的私聊訊息現在將收到設定的自動回覆。
<usetemplate ignoretext="當狀態設定為自動回覆時。" name="okignore" yestext="確定"/>
<usetemplate ignoretext="當線狀態設定為自動回覆時。" name="okignore" yestext="確定"/>
</notification>
<notification name="AutorespondNonFriendsModeSet">
對非好友自動回覆已開啟。
@ -1940,7 +1940,7 @@ URL:[UNTRUSTED_URL]
</notification>
<notification name="RejectTeleportOffersModeWarning">
您目前無法請求傳送,因為「拒絕傳送邀請和請求」功能已啟用。
如需,您可以在「通訊」&gt;「線狀態」菜單下關閉此功能。
如需,您可以在「通訊」&gt;線狀態」菜單下關閉此功能。
<usetemplate name="okbutton" yestext="確定"/>
</notification>
<notification name="RejectFriendshipRequestsModeSet">
@ -3449,7 +3449,7 @@ URL[AUDIOURL]
[MESSAGE]
(根據預設設定,你們將可看到彼此的線狀態。)
(根據預設設定,你們將可看到彼此的線狀態。)
<form name="form">
<button name="Accept" text="接受"/>
<button name="Decline" text="謝絕"/>
@ -3461,7 +3461,7 @@ URL[AUDIOURL]
<notification name="OfferFriendshipNoMessage">
[NAME_SLURL] 想成為你的朋友。
(根據預設設定,你們將可看到彼此的線狀態。)
(根據預設設定,你們將可看到彼此的線狀態。)
<form name="form">
<button name="Accept" text="接受"/>
<button name="Decline" text="謝絕"/>
@ -5501,8 +5501,8 @@ Flickr 驗證失敗。請重試並檢查輸入的程式碼。
<usetemplate name="okbutton" yestext="確定"/>
</notification>
<notification name="GlobalOnlineStatusToggle">
根據伺服器負載情況,切換線狀態的可見性可能需要一段時間才能生效。
<usetemplate ignoretext="提醒我切換狀態的可見性可能需要一些時間。" name="okignore" yestext="確定"/>
根據伺服器負載情況,切換線狀態的可見性可能需要一段時間才能生效。
<usetemplate ignoretext="提醒我切換線狀態的可見性可能需要一些時間。" name="okignore" yestext="確定"/>
</notification>
<notification name="RenderVolumeLODFactorWarning">
警告:細節層次等級 (LOD) 被設定為過高的值。
@ -5697,7 +5697,7 @@ gzip級別6壓縮的測試結果對[FILE]檔案大小[SIZE] KB
<usetemplate name="okbutton" yestext="確定"/>
</notification>
<notification name="WaterExclusionSurfacesWarning">
選中“隱藏水”複選框將覆蓋所選的紋理、凹凸和光澤圖選項。
選中「隱藏水」複選框將覆蓋所選的紋理、凹凸和光澤圖選項。
<usetemplate name="okcancelbuttons" notext="取消" yestext="繼續" />
</notification>
<notification name="EnableAutoFPSWarning">

View File

@ -6,11 +6,11 @@
</layout_panel>
<layout_panel name="lp_friend_list">
<fs_scroll_list name="friend_list">
<fs_scroll_list.column name="icon_online_status" tool_tip="狀態" />
<fs_scroll_list.column name="icon_online_status" tool_tip="線狀態" />
<fs_scroll_list.column label="使用者名稱" name="user_name" tool_tip="該好友的使用者名稱。" />
<fs_scroll_list.column label="顯示名" name="display_name" tool_tip="該好友的顯示名。" />
<fs_scroll_list.column label="姓名" name="full_name" tool_tip="該好友的姓名。" />
<fs_scroll_list.column name="icon_visible_online" tool_tip="該好友可以看到您是否上上。" />
<fs_scroll_list.column name="icon_visible_online" tool_tip="該好友可以看到您是否線。" />
<fs_scroll_list.column name="icon_visible_map" tool_tip="該好友可以在地圖上看到您的位置。" />
<fs_scroll_list.column name="icon_edit_mine" tool_tip="該好友可以編輯、刪除或取得您的物件。" />
<fs_scroll_list.column name="icon_visible_map_theirs" tool_tip="您可以在地圖上看到該好友的位置。" />

View File

@ -30,6 +30,6 @@
<check_box label="允許精簡您的化身" name="alow_self_impostor" tool_tip="如果啟用,檢視器可以將您的化身精簡顯示" />
<check_box label="顯示最佳化後的彩現時間" name="show_tuned_art" tool_tip="如果啟用,時間欄將顯示當前彩現時間,而不是最佳化前的彩現時間。" />
<text name="sundry_desc1">
這些選項控制更精細的參數。請使用線幫助頁面取得更多有關其操作的資訊。
這些選項控制更精細的參數。請使用線幫助頁面取得更多有關其操作的資訊。
</text>
</panel>

View File

@ -61,7 +61,7 @@
<button name="gear_btn" tool_tip="對選擇的人採取操作" />
<menu_button name="friends_view_btn" tool_tip="檢查/排序的選項" />
<button name="friends_add_btn" tool_tip="向某位居民發出交友邀請" />
<button name="GlobalOnlineStatusToggle" tool_tip="切換全域狀態可見性" />
<button name="GlobalOnlineStatusToggle" tool_tip="切換全域線狀態可見性" />
<dnd_button name="friends_del_btn" tool_tip="將選擇的人從朋友名單移除" />
</panel>
<accordion name="friends_accordion">

View File

@ -30,6 +30,6 @@
<check_box label="允許精簡您的化身" name="alow_self_impostor" tool_tip="如果啟用,檢視器可以將您的化身精簡顯示" />
<check_box label="顯示最佳化後的彩現時間" name="show_tuned_art" tool_tip="如果啟用,時間欄將顯示當前彩現時間,而不是最佳化前的彩現時間。" />
<text name="sundry_desc1">
這些選項控制更精細的參數。請使用線幫助頁面取得更多有關其操作的資訊。
這些選項控制更精細的參數。請使用線幫助頁面取得更多有關其操作的資訊。
</text>
</panel>

View File

@ -4,7 +4,7 @@
<button label="設定" name="set_backup_settings_path" />
<layout_stack name="ls_account_specific_label">
<layout_panel name="lp_account_specific_label">
<text name="account_specific_label">您當前處於離線狀態。請注意, 只有當您線時,才能備份和恢復與您的帳戶相關的設定。 然而,適用於所有帳戶的設定可以在離線狀態下備份。</text>
<text name="account_specific_label">您當前處於離線狀態。請注意, 只有當您線時,才能備份和恢復與您的帳戶相關的設定。 然而,適用於所有帳戶的設定可以在離線狀態下備份。</text>
</layout_panel>
<layout_panel name="lp_buttons">
<text name="settings_restored_label">要恢復的設定組(備份始終包括全部):</text>

View File

@ -213,6 +213,7 @@
<combo_box.item label="少量" name="32" />
<combo_box.item label="中等" name="64" />
<combo_box.item label="很多" name="128" />
<combo_box.item label="超多" name="256" />
</combo_box>
<text name="TonemapTypeText">
色調映射器:

View File

@ -9,7 +9,7 @@
<button label="清除歷史記錄" tool_tip="清除搜尋和傳送歷史記錄,以及網頁和紋理快取" name="clear_webcache" />
<text name="cache_size_label">(地點、圖片、網頁、搜尋)</text>
<check_box label="在搜尋結果中顯示我的個人檔案資訊" name="online_searchresults" />
<check_box label="只有我的朋友和群組知道我上上" name="online_visibility" />
<check_box label="只有我的朋友和群組知道我線" name="online_visibility" />
<check_box label="只有我的朋友和群組可以呼叫我或傳送私聊" name="voice_call_friends_only_check" />
<check_box label="顯示已加入的群組邀請" name="FSShowJoinedGroupInvitations" />
<check_box label="語音通話結束後自動關閉麥克風" name="auto_disengage_mic_check" />
@ -58,7 +58,7 @@
<check_box label="限制與頭部的距離限制:" name="LimitLookAt" tool_tip="將你的注視點鎖定在目標的頭部周圍。" />
</panel>
<panel label="自動回復 1" name="tab-autoresponse-1">
<text name="autorespond_toggle_location_tip">注意:要啟用自動回覆訊息,請在「通訊」選單中設定您的線狀態</text>
<text name="autorespond_toggle_location_tip">注意:要啟用自動回覆訊息,請在「通訊」選單中設定您的線狀態</text>
<text name="text_box3">「請勿打擾」模式下的自動回覆:</text>
<text name="autorespond_response_label">當我處於「自動回復」模式時對所有居民的自動回覆:</text>
<text name="autorespond_nf_response_label">當我處於「自動回復陌生人」模式時的自動回覆:</text>

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