From c609a45c26dae083cedc8d06566564cb55d2e72e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 17 Apr 2024 16:58:48 +0200 Subject: [PATCH 01/14] secondlife/viewer#912 BugSplat Crash 1412267 (missed refactoring for FindModel) # Conflicts: # indra/newview/llmodelpreview.cpp --- indra/newview/llmodelpreview.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 29ab4e38c0..4ac3abd747 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -132,7 +132,7 @@ std::string getLodSuffix(S32 lod) return suffix; } -void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +static bool FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) { for (auto scene_iter = scene.begin(); scene_iter != scene.end(); scene_iter++) { @@ -142,10 +142,11 @@ void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LL { baseModelOut = model_iter->mModel; matOut = scene_iter->first; - return; + return true; } } } + return false; } //----------------------------------------------------------------------------- @@ -319,10 +320,8 @@ void LLModelPreview::rebuildUploadData() mat *= scale_mat; - for (auto model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { // for each instance with said transform applied - LLModelInstance instance = *model_iter; - + for (LLModelInstance& instance : iter->second) + { //for each instance with said transform applied LLModel* base_model = instance.mModel; if (base_model && !requested_name.empty()) @@ -354,7 +353,7 @@ void LLModelPreview::rebuildUploadData() } else { - //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for + // Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for extensionLOD = mPhysicsSearchLOD; } @@ -365,9 +364,9 @@ void LLModelPreview::rebuildUploadData() name_to_match += toAdd; } - FindModel(mScene[i], name_to_match, lod_model, transform); + bool found = FindModel(mScene[i], name_to_match, lod_model, transform); - if (!lod_model && i != LLModel::LOD_PHYSICS) + if (!found && i != LLModel::LOD_PHYSICS) { if (mImporterDebug) { @@ -380,7 +379,7 @@ void LLModelPreview::rebuildUploadData() } int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; - while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) + for (; searchLOD <= LLModel::LOD_HIGH; ++searchLOD) { std::string name_to_match = instance.mLabel; llassert(!name_to_match.empty()); @@ -394,8 +393,8 @@ void LLModelPreview::rebuildUploadData() // See if we can find an appropriately named model in LOD 'searchLOD' // - FindModel(mScene[searchLOD], name_to_match, lod_model, transform); - searchLOD++; + if (FindModel(mScene[searchLOD], name_to_match, lod_model, transform)) + break; } } } @@ -1174,8 +1173,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) LLModel* found_model = NULL; LLMatrix4 transform; - FindModel(mBaseScene, loaded_name, found_model, transform); - if (found_model) + if (FindModel(mBaseScene, loaded_name, found_model, transform)) { // don't rename correctly named models (even if they are placed in a wrong order) name_based = true; } From 497c309a5b148fd86a0e1429343092f0a6ca2e0d Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 1 Apr 2025 15:02:24 +0300 Subject: [PATCH 02/14] #912 Refactor FindModel() --- indra/newview/llmodelpreview.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 4ac3abd747..5a8fd299bf 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -132,16 +132,16 @@ std::string getLodSuffix(S32 lod) return suffix; } -static bool FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +static bool FindModel(const LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) { - for (auto scene_iter = scene.begin(); scene_iter != scene.end(); scene_iter++) + for (const auto& scene_pair : scene) { - for (auto model_iter = scene_iter->second.begin(); model_iter != scene_iter->second.end(); model_iter++) + for (const auto& model_iter : scene_pair.second) { - if (model_iter->mModel && (model_iter->mModel->mLabel == name_to_match)) + if (model_iter.mModel && (model_iter.mModel->mLabel == name_to_match)) { - baseModelOut = model_iter->mModel; - matOut = scene_iter->first; + baseModelOut = model_iter.mModel; + matOut = scene_pair.first; return true; } } From 945b965fc237a37d44f4fa57188b369e3f4a693d Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 1 Apr 2025 19:42:21 +0300 Subject: [PATCH 03/14] Add file pattern and recursive directory processing fix_xml_indentations.py --- scripts/code_tools/fix_xml_indentations.py | 54 +++++++++++++++++----- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/scripts/code_tools/fix_xml_indentations.py b/scripts/code_tools/fix_xml_indentations.py index e317e4f7f6..a196b0b7d4 100644 --- a/scripts/code_tools/fix_xml_indentations.py +++ b/scripts/code_tools/fix_xml_indentations.py @@ -86,21 +86,37 @@ def save_xml(tree, file_path, xml_decl, indent_text=False, indent_tab=False, rm_ except IOError as e: print(f"Error saving file {file_path}: {e}") -def process_directory(directory_path, indent_text=False, indent_tab=False, rm_space=False, rewrite_decl=False): +def process_xml_files(file_paths, indent_text=False, indent_tab=False, rm_space=False, rewrite_decl=False): + found_files = False + if file_paths: + found_files = True + for file_path in file_paths: + xml_decl = get_xml_declaration(file_path) + tree = parse_xml_file(file_path) + if tree is not None: + save_xml(tree, file_path, xml_decl, indent_text, indent_tab, rm_space, rewrite_decl) + return found_files + +def process_directory(directory_path, indent_text=False, indent_tab=False, rm_space=False, rewrite_decl=False, file_pattern=None, recursive=False): if not os.path.isdir(directory_path): print(f"Directory not found: {directory_path}") return - xml_files = glob.glob(os.path.join(directory_path, "*.xml")) - if not xml_files: - print(f"No XML files found in directory: {directory_path}") - return + pattern = file_pattern if file_pattern else "*.xml" + found_files = False - for file_path in xml_files: - xml_decl = get_xml_declaration(file_path) - tree = parse_xml_file(file_path) - if tree is not None: - save_xml(tree, file_path, xml_decl, indent_text, indent_tab, rm_space, rewrite_decl) + if not recursive: + # Non-recursive mode + xml_files = glob.glob(os.path.join(directory_path, pattern)) + found_files = process_xml_files(xml_files, indent_text, indent_tab, rm_space, rewrite_decl) + else: + # Recursive mode + for root, dirs, files in os.walk(directory_path): + xml_files = glob.glob(os.path.join(root, pattern)) + found_files = process_xml_files(xml_files, indent_text, indent_tab, rm_space, rewrite_decl) + + if not found_files: + print(f"No XML files found in {'directory tree' if recursive else 'directory'}: {directory_path}") if __name__ == "__main__": if len(sys.argv) < 2 or '--help' in sys.argv: @@ -112,9 +128,13 @@ if __name__ == "__main__": print(" --indent-tab Uses tabs instead of spaces for indentation.") print(" --rm-space Removes spaces in self-closing tags.") print(" --rewrite_decl Replaces the XML declaration line.") + print(" --file Only process files matching the pattern") + print(" --recursive Process files in all subdirectories") print("\nCommon Usage:") print(" To format XML files with text indentation, tab indentation, and removal of spaces in self-closing tags:") print(" python fix_xml_indentations.py /path/to/xmls --indent-text --indent-tab --rm-space") + print("\n To format specific XML files recursively through all subdirectories:") + print(" python fix_xml_indentations.py /path/to/xmls --file floater_*.xml --recursive") sys.exit(1) directory_path = sys.argv[1] @@ -122,4 +142,16 @@ if __name__ == "__main__": indent_tab = '--indent-tab' in sys.argv rm_space = '--rm-space' in sys.argv rewrite_decl = '--rewrite_decl' in sys.argv - process_directory(directory_path, indent_text, indent_tab, rm_space, rewrite_decl) + recursive = '--recursive' in sys.argv + + # Get file pattern if specified + file_pattern = None + if '--file' in sys.argv: + try: + file_index = sys.argv.index('--file') + 1 + if file_index < len(sys.argv): + file_pattern = sys.argv[file_index] + except ValueError: + pass + + process_directory(directory_path, indent_text, indent_tab, rm_space, rewrite_decl, file_pattern, recursive) From 3a03c5f8fe00ae23a33c823625052f39fb42501e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 1 Apr 2025 16:30:21 +0300 Subject: [PATCH 04/14] #3846 Crash at updateGLTFMaterials --- indra/newview/lllocalbitmaps.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 75c77e9301..e31fbb188a 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -700,11 +700,15 @@ void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) // do not create a new material, reuse existing pointer // so that mTextureEntires remains untouched LLGLTFMaterial* render_mat = entry->getGLTFRenderMaterial(); - if (render_mat) + if (render_mat && render_mat != mat) { *render_mat = *mat; render_mat->applyOverride(*override_mat); // can update mGLTFMaterialWithLocalTextures } + else + { + LL_WARNS() << "A TE had an override, but no render material" << LL_ENDL; + } } } } From 8c20662ff77a9672917aa127f80a2fa9efda7119 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 1 Apr 2025 20:35:52 +0300 Subject: [PATCH 05/14] #3712 CMakeFindFrameworks deprecation --- indra/cmake/Linking.cmake | 1 - indra/llwindow/CMakeLists.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake index 1d757abeff..1093fc7f71 100644 --- a/indra/cmake/Linking.cmake +++ b/indra/cmake/Linking.cmake @@ -67,7 +67,6 @@ elseif (WINDOWS) legacy_stdio_definitions ) else() - include(CMakeFindFrameworks) find_library(COREFOUNDATION_LIBRARY CoreFoundation) find_library(CARBON_LIBRARY Carbon) find_library(COCOA_LIBRARY Cocoa) diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 2996f58fe0..5bfac34ca5 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -182,7 +182,6 @@ endif (SDL_FOUND) target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) if (DARWIN) - include(CMakeFindFrameworks) find_library(CARBON_LIBRARY Carbon) target_link_libraries(llwindow ${CARBON_LIBRARY}) endif (DARWIN) From 939817d560434cdc2888ef478b965f5625a381b7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 1 Apr 2025 21:16:38 +0300 Subject: [PATCH 06/14] #3849 Crash at LLSelectMgr::updatePointAt --- indra/newview/llselectmgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 3d17446186..be1e64ce54 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -7513,7 +7513,7 @@ void LLSelectMgr::updatePointAt() LLVector3 select_offset; const LLPickInfo& pick = gViewerWindow->getLastPick(); LLViewerObject *click_object = pick.getObject(); - bool was_hud = pick.mPickHUD && !click_object->isHUDAttachment(); + bool was_hud = pick.mPickHUD && click_object && !click_object->isHUDAttachment(); if (click_object && click_object->isSelected() && !was_hud) { // clicked on another object in our selection group, use that as target From d77954ef50f300846eb14034a8dde3e4d7064dcf Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 2 Apr 2025 01:50:21 +0300 Subject: [PATCH 07/14] #3597 Improve error handling at LLGLSLShader::disableTexture() --- indra/llrender/llglslshader.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index b3f32fdc83..50e40a3eb6 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1247,23 +1247,40 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) llassert(false); return -1; } + S32 index = mTexture[uniform]; - if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE) + if (index < 0) { - if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode) + // Invalid texture index - nothing to disable + return index; + } + + LLTexUnit* tex_unit = gGL.getTexUnit(index); + if (!tex_unit) + { + // Invalid texture unit + LL_WARNS_ONCE("Shader") << "Invalid texture unit at index: " << index << LL_ENDL; + return index; + } + + LLTexUnit::eTextureType curr_type = tex_unit->getCurrType(); + if (curr_type != LLTexUnit::TT_NONE) + { + if (gDebugGL && curr_type != mode) { if (gDebugSession) { - gFailLog << "Texture channel " << index << " texture type corrupted." << std::endl; + gFailLog << "Texture channel " << index << " texture type corrupted. Expected: " << mode << ", Found: " << curr_type << std::endl; ll_fail("LLGLSLShader::disableTexture failed"); } else { - LL_ERRS() << "Texture channel " << index << " texture type corrupted." << LL_ENDL; + LL_ERRS() << "Texture channel " << index << " texture type corrupted. Expected: " << mode << ", Found: " << curr_type << LL_ENDL; } } - gGL.getTexUnit(index)->disable(); + tex_unit->disable(); } + return index; } From db2c45ba23a10d34d89f556533f80a8b42600bf6 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 2 Apr 2025 17:22:17 +0300 Subject: [PATCH 08/14] #3857 pick new and updated LEAP functions from develop branch --- indra/newview/llagentlistener.cpp | 387 +++++++++++++++--- indra/newview/llagentlistener.h | 17 +- indra/newview/llfloaterimnearbychat.cpp | 3 + .../newview/llfloaterimnearbychatlistener.cpp | 34 +- indra/newview/llfloaterimnearbychatlistener.h | 6 +- 5 files changed, 371 insertions(+), 76 deletions(-) diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 0c120ae01d..5ddb87558a 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -31,19 +31,25 @@ #include "llagentlistener.h" #include "llagent.h" +#include "llagentcamera.h" +#include "llavatarname.h" +#include "llavatarnamecache.h" #include "llvoavatar.h" #include "llcommandhandler.h" +#include "llinventorymodel.h" #include "llslurl.h" #include "llurldispatcher.h" +#include "llviewercontrol.h" #include "llviewernetwork.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llvoavatarself.h" #include "llsdutil.h" #include "llsdutil_math.h" #include "lltoolgrab.h" #include "llhudeffectlookat.h" -#include "llagentcamera.h" +#include "llviewercamera.h" LLAgentListener::LLAgentListener(LLAgent &agent) : LLEventAPI("LLAgent", @@ -69,13 +75,6 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("resetAxes", "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])", &LLAgentListener::resetAxes); - add("getAxes", - "Obsolete - use getPosition instead\n" - "Send information about the agent's orientation on [\"reply\"]:\n" - "[\"euler\"]: map of {roll, pitch, yaw}\n" - "[\"quat\"]: array of [x, y, z, w] quaternion values", - &LLAgentListener::getAxes, - LLSDMap("reply", LLSD())); add("getPosition", "Send information about the agent's position and orientation on [\"reply\"]:\n" "[\"region\"]: array of region {x, y, z} position\n" @@ -87,33 +86,34 @@ LLAgentListener::LLAgentListener(LLAgent &agent) add("startAutoPilot", "Start the autopilot system using the following parameters:\n" "[\"target_global\"]: array of target global {x, y, z} position\n" - "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n" + "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]\n" "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n" "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" - "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]" - "[\"allow_flying\"]: allow flying during autopilot [default: True]", - //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n" - //"[\"callback_data\"]: data to send back during a callback [default: none]", - &LLAgentListener::startAutoPilot); + "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]\n" + "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" + "event with [\"success\"] flag is sent to 'LLAutopilot' event pump, when auto pilot is terminated", + &LLAgentListener::startAutoPilot, + llsd::map("target_global", LLSD())); add("getAutoPilot", "Send information about current state of the autopilot system to [\"reply\"]:\n" "[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n" "[\"target_global\"]: array of target global {x, y, z} position\n" "[\"leader_id\"]: uuid of target autopilot is following\n" - "[\"stop_distance\"]: target maximum distance from target\n" + "[\"stop_distance\"]: maximum stop distance from target\n" "[\"target_distance\"]: last known distance from target\n" "[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n" "[\"target_facing\"]: array of {x, y} target direction to face\n" "[\"rotation_threshold\"]: target maximum angle from target facing rotation\n" "[\"behavior_name\"]: name of the autopilot behavior", &LLAgentListener::getAutoPilot, - LLSDMap("reply", LLSD())); + llsd::map("reply", LLSD())); add("startFollowPilot", "[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n" "[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n" "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" - "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]", - &LLAgentListener::startFollowPilot); + "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]", + &LLAgentListener::startFollowPilot, + llsd::map("reply", LLSD())); add("setAutoPilotTarget", "Update target for currently running autopilot:\n" "[\"target_global\"]: array of target global {x, y, z} position", @@ -138,6 +138,69 @@ LLAgentListener::LLAgentListener(LLAgent &agent) "[\"contrib\"]: user's land contribution to this group\n", &LLAgentListener::getGroups, LLSDMap("reply", LLSD())); + //camera params are similar to LSL, see https://wiki.secondlife.com/wiki/LlSetCameraParams + add("setCameraParams", + "Set Follow camera params, and then activate it:\n" + "[\"camera_pos\"]: vector3, camera position in region coordinates\n" + "[\"focus_pos\"]: vector3, what the camera is aimed at (in region coordinates)\n" + "[\"focus_offset\"]: vector3, adjusts the camera focus position relative to the target, default is (1, 0, 0)\n" + "[\"distance\"]: float (meters), distance the camera wants to be from its target, default is 3\n" + "[\"focus_threshold\"]: float (meters), sets the radius of a sphere around the camera's target position within which its focus is not affected by target motion, default is 1\n" + "[\"camera_threshold\"]: float (meters), sets the radius of a sphere around the camera's ideal position within which it is not affected by target motion, default is 1\n" + "[\"focus_lag\"]: float (seconds), how much the camera lags as it tries to aim towards the target, default is 0.1\n" + "[\"camera_lag\"]: float (seconds), how much the camera lags as it tries to move towards its 'ideal' position, default is 0.1\n" + "[\"camera_pitch\"]: float (degrees), adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance, default is 0\n" + "[\"behindness_angle\"]: float (degrees), sets the angle in degrees within which the camera is not constrained by changes in target rotation, default is 10\n" + "[\"behindness_lag\"]: float (seconds), sets how strongly the camera is forced to stay behind the target if outside of behindness angle, default is 0\n" + "[\"camera_locked\"]: bool, locks the camera position so it will not move\n" + "[\"focus_locked\"]: bool, locks the camera focus so it will not move", + &LLAgentListener::setFollowCamParams); + add("setFollowCamActive", + "Turns on or off scripted control of the camera using boolean [\"active\"]", + &LLAgentListener::setFollowCamActive, + llsd::map("active", LLSD())); + add("removeCameraParams", + "Reset Follow camera params", + &LLAgentListener::removeFollowCamParams); + + add("playAnimation", + "Play [\"item_id\"] animation locally (by default) or [\"inworld\"] (when set to true)", + &LLAgentListener::playAnimation, + llsd::map("item_id", LLSD(), "reply", LLSD())); + add("stopAnimation", + "Stop playing [\"item_id\"] animation", + &LLAgentListener::stopAnimation, + llsd::map("item_id", LLSD(), "reply", LLSD())); + add("getAnimationInfo", + "Return information about [\"item_id\"] animation", + &LLAgentListener::getAnimationInfo, + llsd::map("item_id", LLSD(), "reply", LLSD())); + + add("getID", + "Return your own avatar ID", + &LLAgentListener::getID, + llsd::map("reply", LLSD())); + + add("getNearbyAvatarsList", + "Return result set key [\"result\"] for nearby avatars in a range of [\"dist\"]\n" + "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n" + "reply contains \"result\" table with \"id\", \"name\", \"global_pos\", \"region_pos\", \"region_id\" fields", + &LLAgentListener::getNearbyAvatarsList, + llsd::map("reply", LLSD())); + + add("getNearbyObjectsList", + "Return result set key [\"result\"] for nearby objects in a range of [\"dist\"]\n" + "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n" + "reply contains \"result\" table with \"id\", \"global_pos\", \"region_pos\", \"region_id\" fields", + &LLAgentListener::getNearbyObjectsList, + llsd::map("reply", LLSD())); + + add("getAgentScreenPos", + "Return screen position of the [\"avatar_id\"] avatar or own avatar if not specified\n" + "reply contains \"x\", \"y\" coordinates and \"onscreen\" flag to indicate if it's actually in within the current window\n" + "avatar render position is used as the point", + &LLAgentListener::getAgentScreenPos, + llsd::map("reply", LLSD())); } void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -168,7 +231,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const //mAgent.getAvatarObject()->sitOnObject(); // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand() // *TODO - find a permanent place to share this code properly. - + Response response(LLSD(), event_data); LLViewerObject *object = NULL; if (event_data.has("obj_uuid")) { @@ -177,7 +240,13 @@ void LLAgentListener::requestSit(LLSD const & event_data) const else if (event_data.has("position")) { LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); - object = findObjectClosestTo(target_position); + object = findObjectClosestTo(target_position, true); + } + else + { + //just sit on the ground + mAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + return; } if (object && object->getPCode() == LL_PCODE_VOLUME) @@ -194,8 +263,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const } else { - LL_WARNS() << "LLAgent requestSit could not find the sit target: " - << event_data << LL_ENDL; + response.error("requestSit could not find the sit target"); } } @@ -205,7 +273,7 @@ void LLAgentListener::requestStand(LLSD const & event_data) const } -LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const +LLViewerObject * LLAgentListener::findObjectClosestTo(const LLVector3 & position, bool sit_target) const { LLViewerObject *object = NULL; @@ -216,8 +284,13 @@ LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & positio while (cur_index < num_objects) { LLViewerObject * cur_object = gObjectList.getObject(cur_index++); - if (cur_object) - { // Calculate distance from the target position + if (cur_object && !cur_object->isAttachment()) + { + if(sit_target && (cur_object->getPCode() != LL_PCODE_VOLUME)) + { + continue; + } + // Calculate distance from the target position LLVector3 target_diff = cur_object->getPositionRegion() - position; F32 distance_to_target = target_diff.length(); if (distance_to_target < min_distance) @@ -296,22 +369,6 @@ void LLAgentListener::resetAxes(const LLSD& event_data) const } } -void LLAgentListener::getAxes(const LLSD& event_data) const -{ - LLQuaternion quat(mAgent.getQuat()); - F32 roll, pitch, yaw; - quat.getEulerAngles(&roll, &pitch, &yaw); - // The official query API for LLQuaternion's [x, y, z, w] values is its - // public member mQ... - LLSD reply = LLSD::emptyMap(); - reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ)); - reply["euler"] = LLSD::emptyMap(); - reply["euler"]["roll"] = roll; - reply["euler"]["pitch"] = pitch; - reply["euler"]["yaw"] = yaw; - sendReply(reply, event_data); -} - void LLAgentListener::getPosition(const LLSD& event_data) const { F32 roll, pitch, yaw; @@ -333,14 +390,13 @@ void LLAgentListener::getPosition(const LLSD& event_data) const void LLAgentListener::startAutoPilot(LLSD const & event_data) { - LLQuaternion target_rotation_value; LLQuaternion* target_rotation = NULL; if (event_data.has("target_rotation")) { - target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); + LLQuaternion target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); target_rotation = &target_rotation_value; } - // *TODO: Use callback_pump and callback_data + F32 rotation_threshold = 0.03f; if (event_data.has("rotation_threshold")) { @@ -360,13 +416,24 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) stop_distance = (F32)event_data["stop_distance"].asReal(); } + std::string behavior_name = LLCoros::getName(); + if (event_data.has("behavior_name")) + { + behavior_name = event_data["behavior_name"].asString(); + } + // Clear follow target, this is doing a path mFollowTarget.setNull(); + auto finish_cb = [](bool success, void*) + { + LLEventPumps::instance().obtain("LLAutopilot").post(llsd::map("success", success)); + }; + mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]), - event_data["behavior_name"], + behavior_name, target_rotation, - NULL, NULL, + finish_cb, NULL, stop_distance, rotation_threshold, allow_flying); @@ -374,7 +441,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data) void LLAgentListener::getAutoPilot(const LLSD& event_data) const { - LLSD reply = LLSD::emptyMap(); + Response reply(LLSD(), event_data); LLSD::Boolean enabled = mAgent.getAutoPilot(); reply["enabled"] = enabled; @@ -403,12 +470,11 @@ void LLAgentListener::getAutoPilot(const LLSD& event_data) const reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold(); reply["behavior_name"] = mAgent.getAutoPilotBehaviorName(); reply["fly"] = (LLSD::Boolean) mAgent.getFlying(); - - sendReply(reply, event_data); } void LLAgentListener::startFollowPilot(LLSD const & event_data) { + Response response(LLSD(), event_data); LLUUID target_id; bool allow_flying = true; @@ -442,6 +508,10 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data) } } } + else + { + return response.error("'leader_id' or 'avatar_name' should be specified"); + } F32 stop_distance = 0.f; if (event_data.has("stop_distance")) @@ -449,13 +519,16 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data) stop_distance = (F32)event_data["stop_distance"].asReal(); } - if (target_id.notNull()) + if (!gObjectList.findObject(target_id)) { - mAgent.setFlying(allow_flying); - mFollowTarget = target_id; // Save follow target so we can report distance later - - mAgent.startFollowPilot(target_id, allow_flying, stop_distance); + std::string target_info = event_data.has("leader_id") ? event_data["leader_id"] : event_data["avatar_name"]; + return response.error(stringize("Target ", std::quoted(target_info), " was not found")); } + + mAgent.setFlying(allow_flying); + mFollowTarget = target_id; // Save follow target so we can report distance later + + mAgent.startFollowPilot(target_id, allow_flying, stop_distance); } void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const @@ -519,3 +592,209 @@ void LLAgentListener::getGroups(const LLSD& event) const } sendReply(LLSDMap("groups", reply), event); } + +/*----------------------------- camera control -----------------------------*/ +// specialize LLSDParam to support (const LLVector3&) arguments -- this +// wouldn't even be necessary except that the relevant LLVector3 constructor +// is explicitly explicit +template <> +class LLSDParam: public LLSDParamBase +{ +public: + LLSDParam(const LLSD& value): value(LLVector3(value)) {} + + operator const LLVector3&() const { return value; } + +private: + LLVector3 value; +}; + +// accept any of a number of similar LLFollowCamMgr methods with different +// argument types, and return a wrapper lambda that accepts LLSD and converts +// to the target argument type +template +auto wrap(void (LLFollowCamMgr::*method)(const LLUUID& source, T arg)) +{ + return [method](LLFollowCamMgr& followcam, const LLUUID& source, const LLSD& arg) + { (followcam.*method)(source, LLSDParam(arg)); }; +} + +// table of supported LLFollowCamMgr methods, +// with the corresponding setFollowCamParams() argument keys +static std::pair> +cam_params[] = +{ + { "camera_pos", wrap(&LLFollowCamMgr::setPosition) }, + { "focus_pos", wrap(&LLFollowCamMgr::setFocus) }, + { "focus_offset", wrap(&LLFollowCamMgr::setFocusOffset) }, + { "camera_locked", wrap(&LLFollowCamMgr::setPositionLocked) }, + { "focus_locked", wrap(&LLFollowCamMgr::setFocusLocked) }, + { "distance", wrap(&LLFollowCamMgr::setDistance) }, + { "focus_threshold", wrap(&LLFollowCamMgr::setFocusThreshold) }, + { "camera_threshold", wrap(&LLFollowCamMgr::setPositionThreshold) }, + { "focus_lag", wrap(&LLFollowCamMgr::setFocusLag) }, + { "camera_lag", wrap(&LLFollowCamMgr::setPositionLag) }, + { "camera_pitch", wrap(&LLFollowCamMgr::setPitch) }, + { "behindness_lag", wrap(&LLFollowCamMgr::setBehindnessLag) }, + { "behindness_angle", wrap(&LLFollowCamMgr::setBehindnessAngle) }, +}; + +void LLAgentListener::setFollowCamParams(const LLSD& event) const +{ + auto& followcam{ LLFollowCamMgr::instance() }; + for (const auto& pair : cam_params) + { + if (event.has(pair.first)) + { + pair.second(followcam, gAgentID, event[pair.first]); + } + } + followcam.setCameraActive(gAgentID, true); +} + +void LLAgentListener::setFollowCamActive(LLSD const & event) const +{ + LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, event["active"]); +} + +void LLAgentListener::removeFollowCamParams(LLSD const & event) const +{ + LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID); +} + +LLViewerInventoryItem* get_anim_item(LLEventAPI::Response &response, const LLSD &event_data) +{ + LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID()); + if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) + { + response.error(stringize("Animation item ", std::quoted(event_data["item_id"].asString()), " was not found")); + return NULL; + } + return item; +} + +void LLAgentListener::playAnimation(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) + { + if (event_data["inworld"].asBoolean()) + { + mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_START); + } + else + { + gAgentAvatarp->startMotion(item->getAssetUUID()); + } + } +} + +void LLAgentListener::stopAnimation(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) + { + gAgentAvatarp->stopMotion(item->getAssetUUID()); + mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); + } +} + +void LLAgentListener::getAnimationInfo(LLSD const &event_data) +{ + Response response(LLSD(), event_data); + if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) + { + // if motion exists, will return existing one + LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID()); + response["anim_info"] = llsd::map("duration", motion->getDuration(), + "is_loop", motion->getLoop(), + "num_joints", motion->getNumJointMotions(), + "asset_id", item->getAssetUUID(), + "priority", motion->getPriority()); + } +} + +void LLAgentListener::getID(LLSD const& event_data) +{ + Response response(llsd::map("id", gAgentID), event_data); +} + +F32 get_search_radius(LLSD const& event_data) +{ + static LLCachedControl render_far_clip(gSavedSettings, "RenderFarClip", 64); + F32 dist = render_far_clip; + if (event_data.has("dist")) + { + dist = llclamp((F32)event_data["dist"].asReal(), 1, 512); + } + return dist * dist; +} + +void LLAgentListener::getNearbyAvatarsList(LLSD const& event_data) +{ + Response response(LLSD(), event_data); + F32 radius = get_search_radius(event_data); + LLVector3d agent_pos = gAgent.getPositionGlobal(); + for (LLCharacter* character : LLCharacter::sInstances) + { + LLVOAvatar* avatar = (LLVOAvatar*)character; + if (avatar && !avatar->isDead() && !avatar->isControlAvatar() && !avatar->isSelf()) + { + if ((dist_vec_squared(avatar->getPositionGlobal(), agent_pos) <= radius)) + { + LLAvatarName av_name; + LLAvatarNameCache::get(avatar->getID(), &av_name); + LLVector3 region_pos = avatar->getCharacterPosition(); + response["result"].append(llsd::map("id", avatar->getID(), "global_pos", ll_sd_from_vector3d(avatar->getPosGlobalFromAgent(region_pos)), + "region_pos", ll_sd_from_vector3(region_pos), "name", av_name.getUserName(), "region_id", avatar->getRegion()->getRegionID())); + } + } + } +} + +void LLAgentListener::getNearbyObjectsList(LLSD const& event_data) +{ + Response response(LLSD(), event_data); + F32 radius = get_search_radius(event_data); + S32 num_objects = gObjectList.getNumObjects(); + LLVector3d agent_pos = gAgent.getPositionGlobal(); + for (S32 i = 0; i < num_objects; ++i) + { + LLViewerObject* object = gObjectList.getObject(i); + if (object && object->getVolume() && !object->isAttachment()) + { + if ((dist_vec_squared(object->getPositionGlobal(), agent_pos) <= radius)) + { + response["result"].append(llsd::map("id", object->getID(), "global_pos", ll_sd_from_vector3d(object->getPositionGlobal()), "region_pos", + ll_sd_from_vector3(object->getPositionRegion()), "region_id", object->getRegion()->getRegionID())); + } + } + } +} + +void LLAgentListener::getAgentScreenPos(LLSD const& event_data) +{ + Response response(LLSD(), event_data); + LLVector3 render_pos; + if (event_data.has("avatar_id") && (event_data["avatar_id"].asUUID() != gAgentID)) + { + LLUUID avatar_id(event_data["avatar_id"]); + for (LLCharacter* character : LLCharacter::sInstances) + { + LLVOAvatar* avatar = (LLVOAvatar*)character; + if (!avatar->isDead() && (avatar->getID() == avatar_id)) + { + render_pos = avatar->getRenderPosition(); + break; + } + } + } + else if (gAgentAvatarp.notNull() && gAgentAvatarp->isValid()) + { + render_pos = gAgentAvatarp->getRenderPosition(); + } + LLCoordGL screen_pos; + response["onscreen"] = LLViewerCamera::getInstance()->projectPosAgentToScreen(render_pos, screen_pos, false); + response["x"] = screen_pos.mX; + response["y"] = screen_pos.mY; +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index c544d089ce..31f50a653f 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -48,7 +48,6 @@ private: void requestStand(LLSD const & event_data) const; void requestTouch(LLSD const & event_data) const; void resetAxes(const LLSD& event_data) const; - void getAxes(const LLSD& event_data) const; void getGroups(const LLSD& event) const; void getPosition(const LLSD& event_data) const; void startAutoPilot(const LLSD& event_data); @@ -58,7 +57,21 @@ private: void stopAutoPilot(const LLSD& event_data) const; void lookAt(LLSD const & event_data) const; - LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; + void setFollowCamParams(LLSD const & event_data) const; + void setFollowCamActive(LLSD const & event_data) const; + void removeFollowCamParams(LLSD const & event_data) const; + + void playAnimation(LLSD const &event_data); + void playAnimation_(const LLUUID& asset_id, const bool inworld); + void stopAnimation(LLSD const &event_data); + void getAnimationInfo(LLSD const &event_data); + + void getID(LLSD const& event_data); + void getNearbyAvatarsList(LLSD const& event_data); + void getNearbyObjectsList(LLSD const& event_data); + void getAgentScreenPos(LLSD const& event_data); + + LLViewerObject * findObjectClosestTo( const LLVector3 & position, bool sit_target = false ) const; private: LLAgent & mAgent; diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 28c651f0cd..db6f9ac22a 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -52,6 +52,7 @@ #include "llfirstuse.h" #include "llfloaterimnearbychat.h" +#include "llfloaterimnearbychatlistener.h" #include "llagent.h" // gAgent #include "llgesturemgr.h" #include "llmultigesture.h" @@ -71,6 +72,8 @@ S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; +static LLFloaterIMNearbyChatListener sChatListener; + constexpr S32 EXPANDED_HEIGHT = 266; constexpr S32 COLLAPSED_HEIGHT = 60; constexpr S32 EXPANDED_MIN_HEIGHT = 150; diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index 43173d3680..b15a32ce40 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -34,12 +34,12 @@ #include "llagent.h" #include "llchat.h" #include "llviewercontrol.h" +#include "stringize.h" +static const F32 CHAT_THROTTLE_PERIOD = 1.f; -LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar) - : LLEventAPI("LLChatBar", - "LLChatBar listener to (e.g.) sendChat, etc."), - mChatbar(chatbar) +LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() : + LLEventAPI("LLChatBar", "LLChatBar listener to (e.g.) sendChat, etc.") { add("sendChat", "Send chat to the simulator:\n" @@ -49,10 +49,18 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyCh &LLFloaterIMNearbyChatListener::sendChat); } - // "sendChat" command -void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const +void LLFloaterIMNearbyChatListener::sendChat(LLSD const& chat_data) { + F64 cur_time = LLTimer::getElapsedSeconds(); + + if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD) + { + LL_WARNS("LLFloaterIMNearbyChatListener") << "'sendChat' was throttled" << LL_ENDL; + return; + } + mLastThrottleTime = cur_time; + // Extract the data std::string chat_text = chat_data["message"].asString(); @@ -81,20 +89,12 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const } // Have to prepend /42 style channel numbers - std::string chat_to_send; - if (channel == 0) + if (channel) { - chat_to_send = chat_text; - } - else - { - chat_to_send += "/"; - chat_to_send += chat_data["channel"].asString(); - chat_to_send += " "; - chat_to_send += chat_text; + chat_text = stringize("/", chat_data["channel"].asString(), " ", chat_text); } // Send it as if it was typed in - mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, ((bool)(channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); + LLFloaterIMNearbyChat::sendChatFromViewer(chat_text, type_o_chat, (channel == 0) && gSavedSettings.getBOOL("PlayChatAnim")); } diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index 96184d95b3..71eba53a9a 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -38,12 +38,12 @@ class LLFloaterIMNearbyChat; class LLFloaterIMNearbyChatListener : public LLEventAPI { public: - LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar); + LLFloaterIMNearbyChatListener(); private: - void sendChat(LLSD const & chat_data) const; + void sendChat(LLSD const & chat_data); - LLFloaterIMNearbyChat & mChatbar; + F64 mLastThrottleTime{0}; }; #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H From 498b244070b47a9f9f14b5b0f026a14274942459 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 2 Apr 2025 22:05:49 +0300 Subject: [PATCH 09/14] # 3826 Physics Material Type does not update for linked objects --- indra/newview/llpanelvolume.cpp | 56 +++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 951dc45a78..2fbdbeaf59 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -576,32 +576,48 @@ void LLPanelVolume::getState( ) return object->getMaterial(); } } func; - bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + bool material_same = selection->getSelectedTEValue( &func, material_code ); std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (editable && single_volume && material_same) - { - mComboMaterial->setEnabled( true ); - if (material_code == LL_MCODE_LIGHT) - { - if (mComboMaterial->getItemCount() == mComboMaterialItemCount) - { - mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); - } - mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); - } - else - { - if (mComboMaterial->getItemCount() != mComboMaterialItemCount) - { - mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); - } - mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); + bool enable_material = editable && single_volume && material_same; + LLCachedControl edit_linked(gSavedSettings, "EditLinkedParts", false); + if (!enable_material && !edit_linked()) + { + LLViewerObject* root = selection->getPrimaryObject(); + while (root && !root->isAvatar() && root->getParent()) + { + LLViewerObject* parent = (LLViewerObject*)root->getParent(); + if (parent->isAvatar()) + { + break; + } + root = parent; } + if (root) + { + material_code = root->getMaterial(); + } + } + + mComboMaterial->setEnabled(enable_material); + + if (material_code == LL_MCODE_LIGHT) + { + if (mComboMaterial->getItemCount() == mComboMaterialItemCount) + { + mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); + } + mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); } else { - mComboMaterial->setEnabled( false ); + if (mComboMaterial->getItemCount() != mComboMaterialItemCount) + { + mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); + } + + mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); } // Physics properties From 46fca6f5bbafcdb2942114ccccdadc1e769955e4 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 3 Apr 2025 12:34:51 +0300 Subject: [PATCH 10/14] #3857 second batch of new or updated LEAP functions --- indra/llcommon/llsdutil.h | 55 +++++++++ indra/newview/CMakeLists.txt | 2 + indra/newview/groupchatlistener.cpp | 94 +++++++++------ indra/newview/groupchatlistener.h | 15 ++- indra/newview/llagentlistener.h | 1 - indra/newview/llappearancelistener.cpp | 158 +++++++++++++++++++++++++ indra/newview/llappearancelistener.h | 46 +++++++ indra/newview/llappearancemgr.cpp | 8 ++ indra/newview/llappearancemgr.h | 1 + indra/newview/llgroupactions.cpp | 2 +- indra/newview/llwearableitemslist.cpp | 10 -- indra/newview/llwearableitemslist.h | 9 ++ 12 files changed, 350 insertions(+), 51 deletions(-) create mode 100644 indra/newview/llappearancelistener.cpp create mode 100644 indra/newview/llappearancelistener.h diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 38bbe19ddd..c31030c5ea 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -553,6 +553,61 @@ LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter } // namespace llsd +/***************************************************************************** + * toArray(), toMap() + *****************************************************************************/ +namespace llsd +{ + +// For some T convertible to LLSD, given std::vector myVec, +// toArray(myVec) returns an LLSD array whose entries correspond to the +// items in myVec. +// For some U convertible to LLSD, given function U xform(const T&), +// toArray(myVec, xform) returns an LLSD array whose every entry is +// xform(item) of the corresponding item in myVec. +// toArray() actually works with any container usable with range +// 'for', not just std::vector. +// (Once we get C++20 we can use std::identity instead of this default lambda.) +template +LLSD toArray(const C& container, FUNC&& func = [](const auto& arg) { return arg; }) +{ + LLSD array; + for (const auto& item : container) + { + array.append(std::forward(func)(item)); + } + return array; +} + +// For some T convertible to LLSD, given std::map myMap, +// toMap(myMap) returns an LLSD map whose entries correspond to the +// (key, value) pairs in myMap. +// For some U convertible to LLSD, given function +// std::pair xform(const std::pair&), +// toMap(myMap, xform) returns an LLSD map whose every entry is +// xform(pair) of the corresponding (key, value) pair in myMap. +// toMap() actually works with any container usable with range 'for', not +// just std::map. It need not even be an associative container, as long as +// you pass an xform function that returns std::pair. +// (Once we get C++20 we can use std::identity instead of this default lambda.) +template +LLSD toMap(const C& container, FUNC&& func = [](const auto& arg) { return arg; }) +{ + LLSD map; + for (const auto& pair : container) + { + const auto& [key, value] = std::forward(func)(pair); + map[key] = value; + } + return map; +} + +} // namespace llsd + +/***************************************************************************** + * boost::hash + *****************************************************************************/ + // Specialization for generating a hash value from an LLSD block. namespace boost { diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ed29911a43..fff1597fd9 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -92,6 +92,7 @@ set(viewer_SOURCE_FILES llagentwearables.cpp llanimstatelabels.cpp llappcorehttp.cpp + llappearancelistener.cpp llappearancemgr.cpp llappviewer.cpp llappviewerlistener.cpp @@ -761,6 +762,7 @@ set(viewer_HEADER_FILES llanimstatelabels.h llappcorehttp.h llappearance.h + llappearancelistener.h llappearancemgr.h llappviewer.h llappviewerlistener.h diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index 43507f13e9..ed9e34d1bf 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -2,11 +2,11 @@ * @file groupchatlistener.cpp * @author Nat Goodspeed * @date 2011-04-11 - * @brief Implementation for groupchatlistener. + * @brief Implementation for LLGroupChatListener. * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. + * Copyright (C) 2024, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -34,43 +34,69 @@ // std headers // external library headers // other Linden headers +#include "llchat.h" #include "llgroupactions.h" #include "llimview.h" - -namespace { - void startIm_wrapper(LLSD const & event) - { - LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID()); - sendReply(LLSDMap("session_id", LLSD(session_id)), event); - } - - void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id) - { - LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START); - } -} - - -GroupChatListener::GroupChatListener(): +LLGroupChatListener::LLGroupChatListener(): LLEventAPI("GroupChat", "API to enter, leave, send and intercept group chat messages") { - add("startIM", - "Enter a group chat in group with UUID [\"id\"]\n" + add("startGroupChat", + "Enter a group chat in group with UUID [\"group_id\"]\n" "Assumes the logged-in agent is already a member of this group.", - &startIm_wrapper); - add("endIM", - "Leave a group chat in group with UUID [\"id\"]\n" + &LLGroupChatListener::startGroupChat, + llsd::map("group_id", LLSD())); + add("leaveGroupChat", + "Leave a group chat in group with UUID [\"group_id\"]\n" "Assumes a prior successful startIM request.", - &LLGroupActions::endIM, - llsd::array("id")); - add("sendIM", - "send a groupchat IM", - &send_message_wrapper, - llsd::array("text", "session_id", "group_id")); + &LLGroupChatListener::leaveGroupChat, + llsd::map("group_id", LLSD())); + add("sendGroupIM", + "send a [\"message\"] to group with UUID [\"group_id\"]", + &LLGroupChatListener::sendGroupIM, + llsd::map("message", LLSD(), "group_id", LLSD())); +} + +bool is_in_group(LLEventAPI::Response &response, const LLSD &data) +{ + if (!LLGroupActions::isInGroup(data["group_id"])) + { + response.error(stringize("You are not the member of the group:", std::quoted(data["group_id"].asString()))); + return false; + } + return true; +} + +void LLGroupChatListener::startGroupChat(LLSD const &data) +{ + Response response(LLSD(), data); + if (!is_in_group(response, data)) + { + return; + } + if (LLGroupActions::startIM(data["group_id"]).isNull()) + { + return response.error(stringize("Failed to start group chat session ", std::quoted(data["group_id"].asString()))); + } +} + +void LLGroupChatListener::leaveGroupChat(LLSD const &data) +{ + Response response(LLSD(), data); + if (is_in_group(response, data)) + { + LLGroupActions::endIM(data["group_id"].asUUID()); + } +} + +void LLGroupChatListener::sendGroupIM(LLSD const &data) +{ + Response response(LLSD(), data); + if (!is_in_group(response, data)) + { + return; + } + LLUUID group_id(data["group_id"]); + LLIMModel::sendMessage(data["message"], gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), group_id, IM_SESSION_SEND); } -/* - static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, - const LLUUID& other_participant_id, EInstantMessage dialog); -*/ diff --git a/indra/newview/groupchatlistener.h b/indra/newview/groupchatlistener.h index 3819ac59b7..14cd7266a3 100644 --- a/indra/newview/groupchatlistener.h +++ b/indra/newview/groupchatlistener.h @@ -26,15 +26,20 @@ * $/LicenseInfo$ */ -#if ! defined(LL_GROUPCHATLISTENER_H) -#define LL_GROUPCHATLISTENER_H +#if ! defined(LL_LLGROUPCHATLISTENER_H) +#define LL_LLGROUPCHATLISTENER_H #include "lleventapi.h" -class GroupChatListener: public LLEventAPI +class LLGroupChatListener: public LLEventAPI { public: - GroupChatListener(); + LLGroupChatListener(); + +private: + void startGroupChat(LLSD const &data); + void leaveGroupChat(LLSD const &data); + void sendGroupIM(LLSD const &data); }; -#endif /* ! defined(LL_GROUPCHATLISTENER_H) */ +#endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */ diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index 31f50a653f..b5bea8c0bd 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -62,7 +62,6 @@ private: void removeFollowCamParams(LLSD const & event_data) const; void playAnimation(LLSD const &event_data); - void playAnimation_(const LLUUID& asset_id, const bool inworld); void stopAnimation(LLSD const &event_data); void getAnimationInfo(LLSD const &event_data); diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp new file mode 100644 index 0000000000..65cdf2e11b --- /dev/null +++ b/indra/newview/llappearancelistener.cpp @@ -0,0 +1,158 @@ +/** + * @file llappearancelistener.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llappearancelistener.h" + +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "lltransutil.h" +#include "llwearableitemslist.h" +#include "stringize.h" + +LLAppearanceListener::LLAppearanceListener() + : LLEventAPI("LLAppearance", + "API to wear a specified outfit and wear/remove individual items") +{ + add("wearOutfit", + "Wear outfit by folder id: [\"folder_id\"] OR by folder name: [\"folder_name\"]\n" + "When [\"append\"] is true, outfit will be added to COF\n" + "otherwise it will replace current oufit", + &LLAppearanceListener::wearOutfit); + + add("wearItems", + "Wear items by id: [items_id]", + &LLAppearanceListener::wearItems, + llsd::map("items_id", LLSD(), "replace", LLSD())); + + add("detachItems", + "Detach items by id: [items_id]", + &LLAppearanceListener::detachItems, + llsd::map("items_id", LLSD())); + + add("getOutfitsList", + "Return the table with Outfits info(id and name)", + &LLAppearanceListener::getOutfitsList); + + add("getOutfitItems", + "Return the table of items with info(id : name, wearable_type, is_worn) inside specified outfit folder", + &LLAppearanceListener::getOutfitItems); +} + + +void LLAppearanceListener::wearOutfit(LLSD const &data) +{ + Response response(LLSD(), data); + if (!data.has("folder_id") && !data.has("folder_name")) + { + return response.error("Either [folder_id] or [folder_name] is required"); + } + + bool append = data.has("append") ? data["append"].asBoolean() : false; + if (!LLAppearanceMgr::instance().wearOutfit(data, append)) + { + response.error("Failed to wear outfit"); + } +} + +void LLAppearanceListener::wearItems(LLSD const &data) +{ + const LLSD& items_id{ data["items_id"] }; + uuid_vec_t ids; + if (!items_id.isArray()) + { + ids.push_back(items_id.asUUID()); + } + else // array + { + for (const auto& id : llsd::inArray(items_id)) + { + ids.push_back(id); + } + } + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); +} + +void LLAppearanceListener::detachItems(LLSD const &data) +{ + const LLSD& items_id{ data["items_id"] }; + uuid_vec_t ids; + if (!items_id.isArray()) + { + ids.push_back(items_id.asUUID()); + } + else // array + { + for (const auto& id : llsd::inArray(items_id)) + { + ids.push_back(id); + } + } + LLAppearanceMgr::instance().removeItemsFromAvatar(ids); +} + +void LLAppearanceListener::getOutfitsList(LLSD const &data) +{ + Response response(LLSD(), data); + const LLUUID outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); + + response["outfits"] = llsd::toMap(cat_array, + [](const LLPointer &cat) + { return std::make_pair(cat->getUUID().asString(), cat->getName()); }); +} + +void LLAppearanceListener::getOutfitItems(LLSD const &data) +{ + Response response(LLSD(), data); + LLUUID outfit_id(data["outfit_id"].asUUID()); + LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); + if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + return response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); + } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLFindOutfitItems collector = LLFindOutfitItems(); + gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); + + response["items"] = llsd::toMap(item_array, + [](const LLPointer &it) + { + return std::make_pair( + it->getUUID().asString(), + llsd::map( + "name", it->getName(), + "wearable_type", LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE), + "is_worn", get_is_item_worn(it))); + }); +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h new file mode 100644 index 0000000000..04c5eac2eb --- /dev/null +++ b/indra/newview/llappearancelistener.h @@ -0,0 +1,46 @@ +/** + * @file llappearancelistener.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLAPPEARANCELISTENER_H +#define LL_LLAPPEARANCELISTENER_H + +#include "lleventapi.h" + +class LLAppearanceListener : public LLEventAPI +{ +public: + LLAppearanceListener(); + +private: + void wearOutfit(LLSD const &data); + void wearItems(LLSD const &data); + void detachItems(LLSD const &data); + void getOutfitsList(LLSD const &data); + void getOutfitItems(LLSD const &data); +}; + +#endif // LL_LLAPPEARANCELISTENER_H + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 101aca3823..e9d455ae53 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -31,6 +31,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llappearancelistener.h" #include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llcommandhandler.h" @@ -66,6 +67,8 @@ #include "llavatarpropertiesprocessor.h" +LLAppearanceListener sAppearanceListener; + namespace { const S32 BAKE_RETRY_MAX_COUNT = 5; @@ -4762,6 +4765,11 @@ bool wear_category(const LLSD& query_map, bool append) return false; } +bool LLAppearanceMgr::wearOutfit(const LLSD& query_map, bool append) +{ + return wear_category(query_map, append); +} + class LLWearFolderHandler : public LLCommandHandler { public: diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 6c45a32856..bc7dc9506b 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -60,6 +60,7 @@ public: void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append); void wearOutfitByName(const std::string& name); + bool wearOutfit(const LLSD& query_map, bool append = false); void changeOutfit(bool proceed, const LLUUID& category, bool append); void replaceCurrentOutfit(const LLUUID& new_outfit); void renameOutfit(const LLUUID& outfit_id); diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index ba9c9fa13f..34d96aa024 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -46,7 +46,7 @@ // // Globals // -static GroupChatListener sGroupChatListener; +static LLGroupChatListener sGroupChatListener; class LLGroupHandler : public LLCommandHandler { diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 8ce1a745c3..c708e804b2 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -33,7 +33,6 @@ #include "llagentwearables.h" #include "llappearancemgr.h" -#include "llinventoryfunctions.h" #include "llinventoryicon.h" #include "llgesturemgr.h" #include "lltransutil.h" @@ -41,15 +40,6 @@ #include "llviewermenu.h" #include "llvoavatarself.h" -class LLFindOutfitItems : public LLInventoryCollectFunctor -{ -public: - LLFindOutfitItems() {} - virtual ~LLFindOutfitItems() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -}; - bool LLFindOutfitItems::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 3fe1059176..7a5f29020e 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -32,6 +32,7 @@ #include "llsingleton.h" // newview +#include "llinventoryfunctions.h" #include "llinventoryitemslist.h" #include "llinventorylistitem.h" #include "lllistcontextmenu.h" @@ -507,4 +508,12 @@ protected: LLWearableType::EType mMenuWearableType; }; +class LLFindOutfitItems : public LLInventoryCollectFunctor +{ +public: + LLFindOutfitItems() {} + virtual ~LLFindOutfitItems() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +}; + #endif //LL_LLWEARABLEITEMSLIST_H From dead3c1fca14e8097fdc707fb94572eee6b23dc3 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 3 Apr 2025 15:11:51 +0300 Subject: [PATCH 11/14] #3857 teleport finished/failed event --- indra/newview/llappearancelistener.cpp | 2 +- indra/newview/llviewerparcelmgr.cpp | 24 ++++++++++++++++++++++++ indra/newview/llviewerparcelmgr.h | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index 65cdf2e11b..a6d6e76e02 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -137,7 +137,7 @@ void LLAppearanceListener::getOutfitItems(LLSD const &data) LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - return response.error(stringize(LLTrans::getString("OutfitNotFound"), outfit_id.asString())); + return response.error(stringize("Couldn't find outfit ", outfit_id.asString())); } LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 8e6657b4b9..66a19d3601 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@ // Viewer includes #include "llagent.h" #include "llagentaccess.h" +#include "llcallbacklist.h" #include "llviewerparcelaskplay.h" #include "llviewerwindow.h" #include "llviewercontrol.h" @@ -1750,6 +1751,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use { instance->mTeleportFinishedSignal(instance->mTeleportInProgressPosition, false); } + instance->postTeleportFinished(instance->mTeleportWithinRegion); + instance->mTeleportWithinRegion = false; } parcel->setParcelEnvironmentVersion(parcel_environment_version); LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL; @@ -2719,6 +2722,8 @@ void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos // Local teleport. We already have the agent parcel data. // Emit the signal immediately. getInstance()->mTeleportFinishedSignal(new_pos, local); + + postTeleportFinished(true); } else { @@ -2727,12 +2732,14 @@ void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos // Let's wait for the update and then emit the signal. mTeleportInProgressPosition = new_pos; mTeleportInProgress = true; + mTeleportWithinRegion = local; } } void LLViewerParcelMgr::onTeleportFailed() { mTeleportFailedSignal(); + LLEventPumps::instance().obtain("LLTeleport").post(llsd::map("success", false)); } bool LLViewerParcelMgr::getTeleportInProgress() @@ -2740,3 +2747,20 @@ bool LLViewerParcelMgr::getTeleportInProgress() return mTeleportInProgress // case where parcel data arrives after teleport || gAgent.getTeleportState() > LLAgent::TELEPORT_NONE; // For LOCAL, no mTeleportInProgress } + +void LLViewerParcelMgr::postTeleportFinished(bool local) +{ + auto post = []() + { + LLEventPumps::instance().obtain("LLTeleport").post(llsd::map("success", true)); + }; + if (local) + { + static LLCachedControl teleport_local_delay(gSavedSettings, "TeleportLocalDelay"); + doAfterInterval(post, teleport_local_delay + 0.5f); + } + else + { + post(); + } +} diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 974ea39359..95d693662e 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -295,6 +295,8 @@ public: void onTeleportFailed(); bool getTeleportInProgress(); + void postTeleportFinished(bool local); + static bool isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power); static bool isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); @@ -344,7 +346,9 @@ private: std::vector mObservers; + // Used to communicate between onTeleportFinished() and processParcelProperties() bool mTeleportInProgress; + bool mTeleportWithinRegion{ false }; LLVector3d mTeleportInProgressPosition; teleport_finished_signal_t mTeleportFinishedSignal; teleport_failed_signal_t mTeleportFailedSignal; From f2e7e30cffca1de0a1ee9287753156f8a312b7dd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 3 Apr 2025 20:27:28 +0300 Subject: [PATCH 12/14] #3868 Crash in updateHoveredState according to bugsplat mWrapperPanel is null. --- indra/newview/lltoast.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 84503e66a5..84854a79d4 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -436,6 +436,14 @@ void LLToast::setVisible(bool show) void LLToast::updateHoveredState() { + if (!mWrapperPanel) + { + // Shouldn't be happening. + // mWrapperPanel should have been inited in the constructor + // This needs to be figured out and fixed + llassert(false); + return; + } S32 x, y; LLUI::getInstance()->getMousePositionScreen(&x, &y); From f795ad6d6298a5a2e13a9cf9117f9c1d39475a4f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 3 Apr 2025 21:15:57 +0300 Subject: [PATCH 13/14] #3870 Crash at LLVOAvatarSelf::getJoint() A long standing one --- indra/newview/llvoavatar.h | 2 +- indra/newview/llvoavatarself.cpp | 9 +++++++++ indra/newview/llvoavatarself.h | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 263c3dadf6..a2232d21a2 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -547,7 +547,7 @@ public: U32 renderTransparent(bool first_pass); void renderCollisionVolumes(); void renderBones(const std::string &selected_joint = std::string()); - void renderJoints(); + virtual void renderJoints(); static void deleteCachedImages(bool clearAll=true); static void destroyGL(); static void restoreGL(); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 746ef7cacb..f23af5afa4 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -697,6 +697,7 @@ void LLVOAvatarSelf::idleUpdate(LLAgent &agent, const F64 &time) // virtual LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) { + std::lock_guard lock(mJointMapMutex); LLJoint *jointp = NULL; jointp = LLVOAvatar::getJoint(name); if (!jointp && mScreenp) @@ -714,6 +715,14 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) return jointp; } + +//virtual +void LLVOAvatarSelf::renderJoints() +{ + std::lock_guard lock(mJointMapMutex); + LLVOAvatar::renderJoints(); +} + // virtual bool LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight) { diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 051ac791c0..f9bea41b1d 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -92,6 +92,8 @@ public: /*virtual*/ void requestStopMotion(LLMotion* motion); /*virtual*/ LLJoint* getJoint(const std::string &name); + /*virtual*/ void renderJoints(); + /*virtual*/ bool setVisualParamWeight(const LLVisualParam *which_param, F32 weight); /*virtual*/ bool setVisualParamWeight(const char* param_name, F32 weight); /*virtual*/ bool setVisualParamWeight(S32 index, F32 weight); @@ -103,6 +105,8 @@ private: // helper function. Passed in param is assumed to be in avatar's parameter list. bool setParamWeight(const LLViewerVisualParam *param, F32 weight); + std::mutex mJointMapMutex; // getJoint gets used from mesh thread + /******************************************************************************** ** ** ** STATE From 68f20d542ebbb999d7bebb05c7e4c08ebafdfd89 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 3 Apr 2025 21:55:38 +0300 Subject: [PATCH 14/14] #2702 Increase hover height's limit --- indra/newview/llvoavatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 40312b7f4e..de530976ea 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -122,8 +122,8 @@ extern F32 ANIM_SPEED_MAX; extern F32 ANIM_SPEED_MIN; extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG; -const F32 MAX_HOVER_Z = 2.0; -const F32 MIN_HOVER_Z = -2.0; +const F32 MAX_HOVER_Z = 3.0; +const F32 MIN_HOVER_Z = -3.0; const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f; const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;