diff --git a/doc/contributions.txt b/doc/contributions.txt index 3bc663ca19..799115d67e 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -241,6 +241,7 @@ Ansariel Hiller SL-18432 SL-19140 SL-4126 + SL-20524 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp index ebbdae2e9a..daa8f4850a 100644 --- a/indra/llui/lltransutil.cpp +++ b/indra/llui/lltransutil.cpp @@ -44,7 +44,7 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::setdumpCurrentDirectories(LLError::LEVEL_WARN); + //gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN); LL_ERRS() << "Couldn't load string table " << xml_filename << ". Please reinstall viewer from https://www.firestormviewer.org/choose-your-platform/ and contact https://www.firestormviewer.org/support if issue persists after reinstall." << LL_ENDL; return false; } diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index fb7686170b..32380e481b 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -197,7 +197,13 @@ public: // windows only DirectInput8 for joysticks virtual void* getDirectInput8() { return NULL; }; - virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; }; + virtual bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) + { + return false; + }; virtual S32 getRefreshRate() { return mRefreshRate; } protected: diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 9f001433ff..04a5125e8d 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -27,6 +27,7 @@ #include #include +#include #include "llopenglview-objc.h" #include "llwindowmacosx-objc.h" #include "llappdelegate-objc.h" diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index c3382e06c5..373ea80f95 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -43,6 +43,13 @@ #include #include +#include +#include +#include +#include +#include +#include + extern BOOL gDebugWindowProc; BOOL gHiDPISupport = TRUE; @@ -221,13 +228,16 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) { - if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + //if (mask!=MASK_NONE) { - key = gKeyboard->inverseTranslateKey('Y'); - } - else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) - { - key = gKeyboard->inverseTranslateKey('Z'); + if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + { + key = gKeyboard->inverseTranslateKey('Y'); + } + else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + { + key = gKeyboard->inverseTranslateKey('Z'); + } } mRawKeyEvent = event; @@ -1838,6 +1848,488 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) } } +// String should match ndof, so string mapping code was copied as is +static char mapChar( char c ) +{ + unsigned char uc = ( unsigned char ) c; + + switch( uc ) + { + case '/': return '-'; // use dash instead of slash + + case 0x7F: return ' '; + case 0x80: return 'A'; + case 0x81: return 'A'; + case 0x82: return 'C'; + case 0x83: return 'E'; + case 0x84: return 'N'; + case 0x85: return 'O'; + case 0x86: return 'U'; + case 0x87: return 'a'; + case 0x88: return 'a'; + case 0x89: return 'a'; + case 0x8A: return 'a'; + case 0x8B: return 'a'; + case 0x8C: return 'a'; + case 0x8D: return 'c'; + case 0x8E: return 'e'; + case 0x8F: return 'e'; + case 0x90: return ' '; + case 0x91: return ' '; // ? ' + case 0x92: return ' '; // ? ' + case 0x93: return ' '; // ? " + case 0x94: return ' '; // ? " + case 0x95: return ' '; + case 0x96: return ' '; + case 0x97: return ' '; + case 0x98: return ' '; + case 0x99: return ' '; + case 0x9A: return ' '; + case 0x9B: return 0x27; + case 0x9C: return 0x22; + case 0x9D: return ' '; + case 0x9E: return ' '; + case 0x9F: return ' '; + case 0xA0: return ' '; + case 0xA1: return ' '; + case 0xA2: return ' '; + case 0xA3: return ' '; + case 0xA4: return ' '; + case 0xA5: return ' '; + case 0xA6: return ' '; + case 0xA7: return ' '; + case 0xA8: return ' '; + case 0xA9: return ' '; + case 0xAA: return ' '; + case 0xAB: return ' '; + case 0xAC: return ' '; + case 0xAD: return ' '; + case 0xAE: return ' '; + case 0xAF: return ' '; + case 0xB0: return ' '; + case 0xB1: return ' '; + case 0xB2: return ' '; + case 0xB3: return ' '; + case 0xB4: return ' '; + case 0xB5: return ' '; + case 0xB6: return ' '; + case 0xB7: return ' '; + case 0xB8: return ' '; + case 0xB9: return ' '; + case 0xBA: return ' '; + case 0xBB: return ' '; + case 0xBC: return ' '; + case 0xBD: return ' '; + case 0xBE: return ' '; + case 0xBF: return ' '; + case 0xC0: return ' '; + case 0xC1: return ' '; + case 0xC2: return ' '; + case 0xC3: return ' '; + case 0xC4: return ' '; + case 0xC5: return ' '; + case 0xC6: return ' '; + case 0xC7: return ' '; + case 0xC8: return ' '; + case 0xC9: return ' '; + case 0xCA: return ' '; + case 0xCB: return 'A'; + case 0xCC: return 'A'; + case 0xCD: return 'O'; + case 0xCE: return ' '; + case 0xCF: return ' '; + case 0xD0: return '-'; + case 0xD1: return '-'; + case 0xD2: return 0x22; + case 0xD3: return 0x22; + case 0xD4: return 0x27; + case 0xD5: return 0x27; + case 0xD6: return '-'; // use dash instead of slash + case 0xD7: return ' '; + case 0xD8: return 'y'; + case 0xD9: return 'Y'; + case 0xDA: return '-'; // use dash instead of slash + case 0xDB: return ' '; + case 0xDC: return '<'; + case 0xDD: return '>'; + case 0xDE: return ' '; + case 0xDF: return ' '; + case 0xE0: return ' '; + case 0xE1: return ' '; + case 0xE2: return ','; + case 0xE3: return ','; + case 0xE4: return ' '; + case 0xE5: return 'A'; + case 0xE6: return 'E'; + case 0xE7: return 'A'; + case 0xE8: return 'E'; + case 0xE9: return 'E'; + case 0xEA: return 'I'; + case 0xEB: return 'I'; + case 0xEC: return 'I'; + case 0xED: return 'I'; + case 0xEE: return 'O'; + case 0xEF: return 'O'; + case 0xF0: return ' '; + case 0xF1: return 'O'; + case 0xF2: return 'U'; + case 0xF3: return 'U'; + case 0xF4: return 'U'; + case 0xF5: return '|'; + case 0xF6: return ' '; + case 0xF7: return ' '; + case 0xF8: return ' '; + case 0xF9: return ' '; + case 0xFA: return '.'; + case 0xFB: return ' '; + case 0xFC: return ' '; + case 0xFD: return 0x22; + case 0xFE: return ' '; + case 0xFF: return ' '; + } + return c; +} + +// String should match ndof for manufacturer based search to work +static void sanitizeString( char* inCStr ) +{ + char* charIt = inCStr; + while ( *charIt ) + { + *charIt = mapChar( *charIt ); + charIt++; + } +} + +struct HidDevice +{ + long mAxis; + long mLocalID; + char mProduct[256]; + char mManufacturer[256]; + long mUsage; + long mUsagePage; +}; + +static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) +{ + CFMutableDictionaryRef io_properties = nil; + io_registry_entry_t entry1; + io_registry_entry_t entry2; + kern_return_t rc; + + // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + // try to get parent1 + rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); + + IOObjectRelease( entry1 ); + + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); + // either way, release parent2 + IOObjectRelease( entry2 ); + } + } + if ( KERN_SUCCESS == rc ) + { + // IORegistryEntryCreateCFProperties() succeeded + if ( io_properties != nil ) + { + CFTypeRef dict_element = 0; + // get device info + // try hid dictionary first, if fail then go to usb dictionary + + + dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); + sanitizeString(devicep->mProduct); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); + sanitizeString(devicep->mManufacturer); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); + } + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; + } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); + if ( dict_element ) + { + if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) + { + LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; + } + } + } + + //Add axis, because ndof lib checks sutability by axises as well as other elements + devicep->mAxis = 0; + CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); + if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) + { + long count = CFArrayGetCount( (CFArrayRef) hid_elements ); + for (int i = 0; i < count; ++i) + { + CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); + if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) + { + long type = 0, usage_page = 0, usage = 0; + + CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); + } + if ( type != 0 + && type != kIOHIDElementTypeCollection + && usage_page == kHIDPage_GenericDesktop) + { + switch( usage ) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + devicep->mAxis++; + break; + default: + break; + } + } + } + } + } + + CFRelease(io_properties); + } + else + { + LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; + } + } +} + +HidDevice populate_device( io_object_t io_obj ) +{ + void* interfacep = nullptr; + HidDevice device; + memset( &device, 0, sizeof( HidDevice ) ); + CFMutableDictionaryRef device_dic = 0; + kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); + + if ( KERN_SUCCESS == result + && device_dic ) + { + IOReturn io_result = kIOReturnSuccess; + HRESULT query_result = S_OK; + SInt32 the_score = 0; + IOCFPlugInInterface **the_interface = NULL; + + + io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &the_interface, &the_score ); + if ( io_result == kIOReturnSuccess ) + { + query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); + if ( query_result != S_OK ) + { + LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; + } + IODestroyPlugInInterface( the_interface ); + } + else + { + LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; + } + + if ( interfacep ) + { + result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); + + if ( result != kIOReturnSuccess) + { + LL_WARNS("Joystick") << "open failed" << LL_ENDL; + } + } + // extract needed fields + populate_device_info( io_obj, device_dic, &device ); + + // Release interface + if ( interfacep ) + { + ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); + + ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); + + interfacep = NULL; + } + + CFRelease( device_dic ); + } + else + { + LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; + } + + return device; +} + +static void get_devices(std::list &list_of_devices, + io_iterator_t inIODeviceIterator) +{ + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + io_object_t io_obj = 0; + + while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) + { + HidDevice device = populate_device( io_obj ); + + if (debugLoggingEnabled("Joystick")) + { + list_of_devices.push_back(device); + LL_DEBUGS("Joystick") << "Device axises: " << (S32)device.mAxis + << "Device HIDUsepage: " << (S32)device.mUsagePage + << "Device HIDUsage: " << (S32)device.mUsage + << LL_ENDL; + } + else + { + // Should match ndof + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && device.mUsage == kHIDUsage_Game_3DGameController) + || strstr(device.mManufacturer, "3Dconnexion")) + { + list_of_devices.push_back(device); + } + } + + + // release the device object, it is no longer needed + result = IOObjectRelease( io_obj ); + if ( KERN_SUCCESS != result ) + { + LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; + } + } +} + +bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) +{ + bool return_value = false; + CFMutableDictionaryRef device_dict_ref; + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + + // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. + + // A dictionary to match devices to? + device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); + + // BUG FIX! one reference is consumed by IOServiceGetMatchingServices + CFRetain( device_dict_ref ); + io_iterator_t io_iter = 0; + + // create an IO object iterator + result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + if ( kIOReturnSuccess != result ) + { + LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; + } + + if ( io_iter ) + { + // add all existing devices + std::list device_list; + + get_devices(device_list, io_iter); + + std::list::iterator iter; + + for (iter = device_list.begin(); iter != device_list.end(); ++iter) + { + std::string label(iter->mProduct); + LLSD data; + data["manufacturer"] = std::string(iter->mManufacturer); + data["product"] = label; + + if (osx_callback(label, data, userdata)) + { + break; //found device + } + } + return_value = true; + } + + CFRelease( device_dict_ref ); + return return_value; +} + void LLWindowMacOSX::openFile(const std::string& file_name ) { LL_INFOS() << "Opening file " << file_name << LL_ENDL; diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index babe6f66cc..7af6ecf96b 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -114,6 +114,11 @@ public: F32 getSystemUISize() override; void openFile(const std::string& file_name) override; void setTitle(const std::string& title) override; + + bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) override; static std::vector getDisplaysResolutionList(); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 47c172e32e..87616aa182 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4612,7 +4612,10 @@ void* LLWindowWin32::getDirectInput8() return &gDirectInput8; } -bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata) +bool LLWindowWin32::getInputDevices(U32 device_type_filter, + std::function osx_callback, + void * di8_devices_callback, + void* userdata) { if (gDirectInput8 != NULL) { diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 239a0a3516..3dedf63806 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -130,7 +130,10 @@ public: static void setDPIAwareness(); /*virtual*/ void* getDirectInput8(); - /*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata); + /*virtual*/ bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata); U32 getRawWParam() { return mRawWParam; } diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 175031cf9a..a9cb834772 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -859,7 +859,7 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, if (!LLXMLNode::parseFile(filename, root, NULL)) { - LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL; + LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL; return false; } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8b1d8c3105..8ee1c0577d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6517,7 +6517,7 @@ Persist 1 Type - String + LLSD Value diff --git a/indra/newview/fsradarentry.cpp b/indra/newview/fsradarentry.cpp index 146a8512dc..47cdf4621c 100644 --- a/indra/newview/fsradarentry.cpp +++ b/indra/newview/fsradarentry.cpp @@ -35,6 +35,8 @@ #include "llviewerregion.h" #include "rlvhandler.h" +static constexpr char* CAPNAME = "AgentProfile"; + FSRadarEntry::FSRadarEntry(const LLUUID& avid) : mID(avid), mName(LLTrans::getString("AvatarNameWaiting")), @@ -62,16 +64,21 @@ FSRadarEntry::FSRadarEntry(const LLUUID& avid) // NOTE: typically we request these once on creation to avoid excess traffic/processing. //This means updates to these properties won't typically be seen while target is in nearby range. LLAvatarPropertiesProcessor* processor = LLAvatarPropertiesProcessor::getInstance(); - processor->addObserver(mID, this); - processor->sendAvatarNotesRequest(mID); if (auto region = gAgent.getRegion(); region) { if (region->capabilitiesReceived()) { - const bool use_cap = LLGridManager::instance().isInSecondLife() ? true : region->isCapabilityAvailable("AgentProfile"); - processor->sendAvatarPropertiesRequest(mID, use_cap); + if (LLGridManager::instance().isInSecondLife() || region->isCapabilityAvailable(CAPNAME)) + { + processor->sendAvatarPropertiesRequest(mID); + } + else + { + processor->sendAvatarLegacyPropertiesRequest(mID); + processor->sendAvatarNotesRequest(mID); + } } else { @@ -82,8 +89,15 @@ FSRadarEntry::FSRadarEntry(const LLUUID& avid) mRegionCapabilitiesReceivedCallbackConnection.disconnect(); } gAgent.removeRegionChangedCallback(mRegionChangedCallbackConnection); - const bool use_cap = LLGridManager::instance().isInSecondLife() ? true : (reg && reg->isCapabilityAvailable("AgentProfile")); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mID, use_cap); + if (LLGridManager::instance().isInSecondLife() || (reg && reg->isCapabilityAvailable(CAPNAME))) + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mID); + } + else + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest(mID); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(mID); + } }; mRegionChangedCallbackConnection = gAgent.addRegionChangedCallback([this, capsReceivedCb]() @@ -98,8 +112,15 @@ FSRadarEntry::FSRadarEntry(const LLUUID& avid) if (newregion->capabilitiesReceived()) { gAgent.removeRegionChangedCallback(mRegionChangedCallbackConnection); - const bool use_cap = LLGridManager::instance().isInSecondLife() ? true : newregion->isCapabilityAvailable("AgentProfile"); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mID, use_cap); + if (LLGridManager::instance().isInSecondLife() || newregion->isCapabilityAvailable(CAPNAME)) + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mID); + } + else + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest(mID); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(mID); + } } else { @@ -165,7 +186,7 @@ void FSRadarEntry::processProperties(void* data, EAvatarProcessorType type) { if (data) { - if (type == APT_PROPERTIES || type == APT_PROPERTIES_LEGACY) + if (type == APT_PROPERTIES) { LLAvatarData* avatar_data = static_cast(data); if (avatar_data && avatar_data->agent_id == gAgentID && avatar_data->avatar_id == mID) @@ -176,6 +197,17 @@ void FSRadarEntry::processProperties(void* data, EAvatarProcessorType type) else mAge = ((LLDate::now().secondsSinceEpoch() - (avatar_data->born_on).secondsSinceEpoch()) / 86400); checkAge(); + setNotes(avatar_data->notes); + } + } + else if (type == APT_PROPERTIES_LEGACY) + { + LLAvatarData* avatar_data = static_cast(data); + if (avatar_data && avatar_data->agent_id == gAgentID && avatar_data->avatar_id == mID) + { + mStatus = avatar_data->flags; + mAge = ((LLDate::now().secondsSinceEpoch() - (avatar_data->born_on).secondsSinceEpoch()) / 86400); + checkAge(); } } else if (type == APT_NOTES) diff --git a/indra/newview/llagentpicksinfo.cpp b/indra/newview/llagentpicksinfo.cpp index 2d23c937cc..a5f9b178e2 100644 --- a/indra/newview/llagentpicksinfo.cpp +++ b/indra/newview/llagentpicksinfo.cpp @@ -50,10 +50,16 @@ public: void sendAgentPicksRequest() { - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID()); + // OpenSim + //LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID()); + if (!gAgent.getRegionCapability("AgentProfile").empty()) + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID()); + else + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID()); + // } - typedef boost::function server_respond_callback_t; + typedef boost::function server_respond_callback_t; void setServerRespondCallback(const server_respond_callback_t& cb) { @@ -62,10 +68,10 @@ public: virtual void processProperties(void* data, EAvatarProcessorType type) { - if(APT_PICKS == type) + if(APT_PROPERTIES == type) { - LLAvatarPicks* picks = static_cast(data); - if(picks && gAgent.getID() == picks->target_id) + LLAvatarData* picks = static_cast(data); + if(picks && gAgent.getID() == picks->avatar_id) { if(mServerRespondCallback) { @@ -73,6 +79,21 @@ public: } } } + // OpenSim + else if (APT_PICKS == type) + { + LLAvatarPicks* picks = static_cast(data); + if (picks && gAgent.getID() == picks->target_id) + { + if (mServerRespondCallback) + { + LLAvatarData avatardata; + avatardata.picks_list = picks->picks_list; + mServerRespondCallback(&avatardata); + } + } + } + // } private: @@ -118,7 +139,7 @@ bool LLAgentPicksInfo::isPickLimitReached() return getNumberOfPicks() >= LLAgentBenefitsMgr::current().getPicksLimit(); } -void LLAgentPicksInfo::onServerRespond(LLAvatarPicks* picks) +void LLAgentPicksInfo::onServerRespond(LLAvatarData* picks) { if(!picks) { diff --git a/indra/newview/llagentpicksinfo.h b/indra/newview/llagentpicksinfo.h index 21df036cb7..56e7bd0775 100644 --- a/indra/newview/llagentpicksinfo.h +++ b/indra/newview/llagentpicksinfo.h @@ -29,7 +29,7 @@ #include "llsingleton.h" -struct LLAvatarPicks; +struct LLAvatarData; /** * Class that provides information about Agent Picks @@ -74,7 +74,7 @@ public: void decrementNumberOfPicks() { --mNumberOfPicks; } - void onServerRespond(LLAvatarPicks* picks); + void onServerRespond(LLAvatarData* picks); private: diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index 308c1cb43d..20f73b47d1 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -245,7 +245,7 @@ void LLAvatarIconCtrl::setValue(const LLSD& value) // messages. People API already hits the user table. LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI); app->addObserver(mAvatarId, this); - app->sendAvatarPropertiesRequest(mAvatarId); + app->sendAvatarLegacyPropertiesRequest(mAvatarId); } } } @@ -296,7 +296,7 @@ void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type) { if (APT_PROPERTIES_LEGACY == type) { - LLAvatarData* avatar_data = static_cast(data); + LLAvatarLegacyData* avatar_data = static_cast(data); if (avatar_data) { if (avatar_data->avatar_id != mAvatarId) diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 51d26d99d6..b049af23de 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -69,7 +69,7 @@ void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarP // IAN BUG this should update the observer's UUID if this is a dupe - sent to PE if (it == end) { - mObservers.insert(pair(avatar_id, observer)); + mObservers.emplace(avatar_id, observer); } } @@ -117,21 +117,19 @@ void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarPr } // Try to send HTTP request if cap_url is available - if (type == APT_PROPERTIES || type == APT_PICKS || type == APT_GROUPS || type == APT_NOTES) + if (type == APT_PROPERTIES) { - std::string cap_url(gAgent.getRegionCapability("AgentProfile")); + std::string cap_url = gAgent.getRegionCapability("AgentProfile"); if (!cap_url.empty()) { initAgentProfileCapRequest(avatar_id, cap_url, type); - return; } - - // Don't sent UDP request for APT_PROPERTIES - if (type == APT_PROPERTIES) + else { - LL_WARNS() << "No cap_url for APT_PROPERTIES, request is not sent" << LL_ENDL; - return; + // Don't sent UDP request for APT_PROPERTIES + LL_WARNS() << "No cap_url for APT_PROPERTIES, request for " << avatar_id << " is not sent" << LL_ENDL; } + return; } // Send UDP request @@ -158,8 +156,7 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EA // indicate we're going to make a request addPendingRequest(avatar_id, type); - std::vector strings; - strings.push_back(avatar_id.asString()); + std::vector strings{ avatar_id.asString() }; send_generic_message(method, strings); } @@ -171,8 +168,8 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUI msg->newMessageFast(_PREHASH_AvatarPropertiesRequest); msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); msg->addUUIDFast(_PREHASH_AvatarID, avatar_id); gAgent.sendReliableMessage(); } @@ -183,24 +180,14 @@ void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avata LLCoros::instance().launch("requestAgentUserInfoCoro", [cap_url, avatar_id, type]() { requestAvatarPropertiesCoro(cap_url, avatar_id, type); }); } -void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id, bool use_cap) +void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) { - sendRequest(avatar_id, use_cap ? APT_PROPERTIES : APT_PROPERTIES_LEGACY, "AvatarPropertiesRequest"); + sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest"); } -void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) +void LLAvatarPropertiesProcessor::sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id) { - sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest"); -} - -void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id) -{ - sendGenericRequest(avatar_id, APT_NOTES, "avatarnotesrequest"); -} - -void LLAvatarPropertiesProcessor::sendAvatarGroupsRequest(const LLUUID& avatar_id) -{ - sendGenericRequest(avatar_id, APT_GROUPS, "avatargroupsrequest"); + sendRequest(avatar_id, APT_PROPERTIES_LEGACY, "AvatarPropertiesRequest"); } void LLAvatarPropertiesProcessor::sendAvatarTexturesRequest(const LLUUID& avatar_id) @@ -276,19 +263,21 @@ std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_data) { // Special accounts like M Linden don't have payment info revealed. - if (!avatar_data->caption_text.empty()) return ""; + if (!avatar_data->caption_text.empty()) + return ""; // Linden employees don't have payment info revealed - const S32 LINDEN_EMPLOYEE_INDEX = 3; - if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return ""; + constexpr S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) + return ""; - BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED); - BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED); + bool transacted = (avatar_data->flags & AVATAR_TRANSACTED); + bool identified = (avatar_data->flags & AVATAR_IDENTIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations //BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED); const char* payment_text; - if(transacted) + if (transacted) { payment_text = "PaymentInfoUsed"; } @@ -307,17 +296,19 @@ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_ bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avatar_data) { // Special accounts like M Linden don't have payment info revealed. - if (!avatar_data->caption_text.empty()) return true; + if (!avatar_data->caption_text.empty()) + return true; // Linden employees don't have payment info revealed - const S32 LINDEN_EMPLOYEE_INDEX = 3; - if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return true; + constexpr S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) + return true; return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED)); } // static -void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id, EAvatarProcessorType type) +void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t @@ -328,132 +319,108 @@ void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_ur LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); httpOpts->setFollowRedirects(true); - std::string finalUrl = cap_url + "/" + agent_id.asString(); + std::string finalUrl = cap_url + "/" + avatar_id.asString(); LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders); // Response is being processed, no longer pending is required - getInstance()->removePendingRequest(agent_id, type); + getInstance()->removePendingRequest(avatar_id, type); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status || !result.has("id") - || agent_id != result["id"].asUUID()) + || avatar_id != result["id"].asUUID()) { - LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id + LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << avatar_id << (!status ? " (no HTTP status)" : !result.has("id") ? " (no result.id)" : std::string(" (result.id=") + result["id"].asUUID().asString() + ")") << LL_ENDL; return; } - if (type == APT_PROPERTIES) + LLAvatarData avatar_data; + + std::string birth_date; + + avatar_data.agent_id = gAgentID; + avatar_data.avatar_id = avatar_id; + avatar_data.image_id = result["sl_image_id"].asUUID(); + avatar_data.fl_image_id = result["fl_image_id"].asUUID(); + avatar_data.partner_id = result["partner_id"].asUUID(); + avatar_data.about_text = result["sl_about_text"].asString(); + avatar_data.fl_about_text = result["fl_about_text"].asString(); + avatar_data.born_on = result["member_since"].asDate(); + // TODO: SL-20163 Remove the "has" check when SRV-684 is done + // and the field "hide_age" is included to the http response + avatar_data.hide_age = !result.has("hide_age") || result["hide_age"].asBoolean(); + avatar_data.profile_url = getProfileURL(avatar_id.asString()); + avatar_data.customer_type = result["customer_type"].asString(); + avatar_data.notes = result["notes"].asString(); + + avatar_data.flags = 0; + // FIRE-32184: Online/Offline status not working for non-friends + // if (result["online"].asBoolean()) + if (result["online"].isUndefined()) { - LLAvatarData avatar_data; - - std::string birth_date; - - // Fix protocol bug - //avatar_data.agent_id = agent_id; - avatar_data.agent_id = gAgentID; - // - avatar_data.avatar_id = agent_id; - avatar_data.image_id = result["sl_image_id"].asUUID(); - avatar_data.fl_image_id = result["fl_image_id"].asUUID(); - avatar_data.partner_id = result["partner_id"].asUUID(); - avatar_data.about_text = result["sl_about_text"].asString(); - avatar_data.fl_about_text = result["fl_about_text"].asString(); - avatar_data.born_on = result["member_since"].asDate(); - // TODO: SL-20163 Remove the "has" check when SRV-684 is done - // and the field "hide_age" is included to the http response - avatar_data.hide_age = !result.has("hide_age") || result["hide_age"].asBoolean(); - avatar_data.profile_url = getProfileURL(agent_id.asString()); - avatar_data.customer_type = result["customer_type"].asString(); - - avatar_data.flags = 0; - if (result["online"].asBoolean()) - { - avatar_data.flags |= AVATAR_ONLINE; - } - if (result["allow_publish"].asBoolean()) - { - avatar_data.flags |= AVATAR_ALLOW_PUBLISH; - } - if (result["identified"].asBoolean()) - { - avatar_data.flags |= AVATAR_IDENTIFIED; - } - if (result["transacted"].asBoolean()) - { - avatar_data.flags |= AVATAR_TRANSACTED; - } - - avatar_data.caption_index = 0; - if (result.has("charter_member")) // won't be present if "caption" is set - { - avatar_data.caption_index = result["charter_member"].asInteger(); - } - else if (result.has("caption")) - { - avatar_data.caption_text = result["caption"].asString(); - } - - getInstance()->notifyObservers(agent_id, &avatar_data, type); + avatar_data.flags |= AVATAR_ONLINE_UNDEFINED; } - else if (type == APT_PICKS) + else if (result["online"].asBoolean()) + // { - LLAvatarPicks avatar_picks; - - avatar_picks.agent_id = agent_id; // Not in use? - avatar_picks.target_id = agent_id; - - LLSD picks_array = result["picks"]; - for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it) - { - const LLSD& pick_data = *it; - avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); - } - - getInstance()->notifyObservers(agent_id, &avatar_picks, type); + avatar_data.flags |= AVATAR_ONLINE; } - else if (type == APT_GROUPS) + if (result["allow_publish"].asBoolean()) { - LLAvatarGroups avatar_groups; - - avatar_groups.agent_id = agent_id; // Not in use? - avatar_groups.avatar_id = agent_id; // target_id - - LLSD groups_array = result["groups"]; - for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it) - { - const LLSD& group_info = *it; - LLAvatarGroups::LLGroupData group_data; - group_data.group_powers = 0; // Not in use? - group_data.group_title = group_info["name"].asString(); // Missing data, not in use? - group_data.group_id = group_info["id"].asUUID(); - group_data.group_name = group_info["name"].asString(); - group_data.group_insignia_id = group_info["image_id"].asUUID(); - - avatar_groups.group_list.push_back(group_data); - } - - getInstance()->notifyObservers(agent_id, &avatar_groups, type); + avatar_data.flags |= AVATAR_ALLOW_PUBLISH; } - else if (type == APT_NOTES) + if (result["identified"].asBoolean()) { - LLAvatarNotes avatar_notes; - - avatar_notes.agent_id = agent_id; - avatar_notes.target_id = agent_id; - avatar_notes.notes = result["notes"].asString(); - - getInstance()->notifyObservers(agent_id, &avatar_notes, type); + avatar_data.flags |= AVATAR_IDENTIFIED; } + if (result["transacted"].asBoolean()) + { + avatar_data.flags |= AVATAR_TRANSACTED; + } + + avatar_data.caption_index = 0; + if (result.has("charter_member")) // won't be present if "caption" is set + { + avatar_data.caption_index = result["charter_member"].asInteger(); + } + else if (result.has("caption")) + { + avatar_data.caption_text = result["caption"].asString(); + } + + // Groups + LLSD groups_array = result["groups"]; + for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it) + { + const LLSD& group_info = *it; + LLAvatarData::LLGroupData group_data; + group_data.group_powers = 0; // Not in use? + group_data.group_title = group_info["name"].asString(); // Missing data, not in use? + group_data.group_id = group_info["id"].asUUID(); + group_data.group_name = group_info["name"].asString(); + group_data.group_insignia_id = group_info["image_id"].asUUID(); + + avatar_data.group_list.push_back(group_data); + } + + // Picks + LLSD picks_array = result["picks"]; + for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it) + { + const LLSD& pick_data = *it; + avatar_data.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); + } + + getInstance()->notifyObservers(avatar_id, &avatar_data, type); } -void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) +void LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**) { LLAvatarData avatar_data; std::string birth_date; @@ -472,7 +439,7 @@ void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* LLDateUtil::dateFromPDTString(avatar_data.born_on, birth_date); // Since field 'hide_age' is not supported by msg system we'd better hide the age here // OpenSim - //avatar_data.hide_age = TRUE; + //avatar_data.hide_age = true; avatar_data.hide_age = LLGridManager::instance().isInSecondLife(); // avatar_data.caption_index = 0; @@ -493,33 +460,6 @@ void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* self->notifyObservers(avatar_data.avatar_id, &avatar_data, APT_PROPERTIES_LEGACY); } -void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**) -{ -/* - AvatarInterestsReply is automatically sent by the server in response to the - AvatarPropertiesRequest sent when the panel is opened (in addition to the AvatarPropertiesReply message). - If the interests panel is no longer part of the design (?) we should just register the message - to a handler function that does nothing. - That will suppress the warnings and be compatible with old server versions. - WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply -*/ - - LLInterestsData interests_data; - - msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, interests_data.agent_id ); - msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, interests_data.avatar_id ); - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, interests_data.want_to_mask ); - msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_WantToText, interests_data.want_to_text ); - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, interests_data.skills_mask ); - msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_SkillsText, interests_data.skills_text ); - msg->getString( _PREHASH_PropertiesData, _PREHASH_LanguagesText, interests_data.languages_text ); - - LLAvatarPropertiesProcessor* self = getInstance(); - // Request processed, no longer pending - self->removePendingRequest(interests_data.avatar_id, APT_INTERESTS_INFO); - self->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO); -} - void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**) { LLAvatarClassifieds classifieds; @@ -536,7 +476,7 @@ void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg->getUUID(_PREHASH_Data, _PREHASH_ClassifiedID, data.classified_id, n); msg->getString(_PREHASH_Data, _PREHASH_Name, data.name, n); - classifieds.classifieds_list.push_back(data); + classifieds.classifieds_list.emplace_back(data); } LLAvatarPropertiesProcessor* self = getInstance(); @@ -577,6 +517,241 @@ void LLAvatarPropertiesProcessor::processClassifiedInfoReply(LLMessageSystem* ms // } +void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) +{ + LLPickData pick_data; + + // Extract the agent id and verify the message is for this + // client. + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, pick_data.agent_id ); + msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_data.pick_id); + msg->getUUID(_PREHASH_Data, _PREHASH_CreatorID, pick_data.creator_id); + + // ** top_pick should be deleted, not being used anymore - angela + msg->getBOOL(_PREHASH_Data, _PREHASH_TopPick, pick_data.top_pick); + msg->getUUID(_PREHASH_Data, _PREHASH_ParcelID, pick_data.parcel_id); + msg->getString(_PREHASH_Data, _PREHASH_Name, pick_data.name); + msg->getString(_PREHASH_Data, _PREHASH_Desc, pick_data.desc); + msg->getUUID(_PREHASH_Data, _PREHASH_SnapshotID, pick_data.snapshot_id); + + msg->getString(_PREHASH_Data, _PREHASH_User, pick_data.user_name); + msg->getString(_PREHASH_Data, _PREHASH_OriginalName, pick_data.original_name); + msg->getString(_PREHASH_Data, _PREHASH_SimName, pick_data.sim_name); + msg->getVector3d(_PREHASH_Data, _PREHASH_PosGlobal, pick_data.pos_global); + + msg->getS32(_PREHASH_Data, _PREHASH_SortOrder, pick_data.sort_order); + msg->getBOOL(_PREHASH_Data, _PREHASH_Enabled, pick_data.enabled); + + LLAvatarPropertiesProcessor* self = getInstance(); + // don't need to remove pending request as we don't track pick info + self->notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO); +} + +void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id, void* data, EAvatarProcessorType type) +{ + // Copy the map (because observers may delete themselves when updated?) + LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers; + + for (const auto& [agent_id, observer] : observers) + { + // only notify observers for the same agent, or if the observer + // didn't know the agent ID and passed a NULL id. + if (agent_id == id || agent_id.isNull()) + { + observer->processProperties(data, type); + } + } +} + +void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32 rights) +{ + if(!avatar_id.isNull()) + { + LLMessageSystem* msg = gMessageSystem; + + // setup message header + msg->newMessageFast(_PREHASH_GrantUserRights); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); + + msg->nextBlockFast(_PREHASH_Rights); + msg->addUUID(_PREHASH_AgentRelated, avatar_id); + msg->addS32(_PREHASH_RelatedRights, rights); + + gAgent.sendReliableMessage(); + } +} + +void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id ) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessage(_PREHASH_PickDelete); + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_PickID, pick_id); + gAgent.sendReliableMessage(); + + LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); + LLAgentPicksInfo::getInstance()->decrementNumberOfPicks(); +} + +void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_id) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_ClassifiedDelete); + + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_ClassifiedID, classified_id); + + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick) +{ + if (!new_pick) + return; + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_PickInfoUpdate); + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_PickID, new_pick->pick_id); + msg->addUUID(_PREHASH_CreatorID, new_pick->creator_id); + + //legacy var need to be deleted + msg->addBOOL(_PREHASH_TopPick, FALSE); + + // fills in on simulator if null + msg->addUUID(_PREHASH_ParcelID, new_pick->parcel_id); + msg->addString(_PREHASH_Name, new_pick->name); + msg->addString(_PREHASH_Desc, new_pick->desc); + msg->addUUID(_PREHASH_SnapshotID, new_pick->snapshot_id); + msg->addVector3d(_PREHASH_PosGlobal, new_pick->pos_global); + + // Only top picks have a sort order + msg->addS32(_PREHASH_SortOrder, 0); + + msg->addBOOL(_PREHASH_Enabled, new_pick->enabled); + gAgent.sendReliableMessage(); + + LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); +} + +void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data) +{ + if(!c_data) + { + return; + } + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_ClassifiedInfoUpdate); + + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_ClassifiedID, c_data->classified_id); + msg->addU32(_PREHASH_Category, c_data->category); + msg->addString(_PREHASH_Name, c_data->name); + msg->addString(_PREHASH_Desc, c_data->description); + msg->addUUID(_PREHASH_ParcelID, c_data->parcel_id); + msg->addU32(_PREHASH_ParentEstate, 0); + msg->addUUID(_PREHASH_SnapshotID, c_data->snapshot_id); + msg->addVector3d(_PREHASH_PosGlobal, c_data->pos_global); + msg->addU8(_PREHASH_ClassifiedFlags, c_data->flags); + msg->addS32(_PREHASH_PriceForListing, c_data->price_for_listing); + + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id) +{ + // Must ask for a pick based on the creator id because + // the pick database is distributed to the inventory cluster. JC + std::vector request_params{ creator_id.asString(), pick_id.asString() }; + send_generic_message("pickinforequest", request_params); +} + +void LLAvatarPropertiesProcessor::sendClassifiedInfoRequest(const LLUUID& classified_id) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_ClassifiedInfoRequest); + msg->nextBlock(_PREHASH_AgentData); + + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_ClassifiedID, classified_id); + + gAgent.sendReliableMessage(); +} + +bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + timestamp_map_t::iterator it = mRequestTimestamps.find(key); + + // Is this a new request? + if (it == mRequestTimestamps.end()) return false; + + // We found a request, check if it has timed out + U32 now = time(nullptr); + const U32 REQUEST_EXPIRE_SECS = 5; + U32 expires = it->second + REQUEST_EXPIRE_SECS; + + // Request is still pending if it hasn't expired yet + // *NOTE: Expired requests will accumulate in this map, but they are rare, + // the data is small, and they will be updated if the same data is + // re-requested + return (now < expires); +} + +void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + U32 now = time(nullptr); + // Add or update existing (expired) request + mRequestTimestamps[ key ] = now; +} + +void LLAvatarPropertiesProcessor::removePendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + mRequestTimestamps.erase(key); +} + +// OpenSim +void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) +{ + sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest"); +} + +void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id) +{ + sendGenericRequest(avatar_id, APT_NOTES, "avatarnotesrequest"); +} + +void LLAvatarPropertiesProcessor::sendAvatarGroupsRequest(const LLUUID& avatar_id) +{ + sendGenericRequest(avatar_id, APT_GROUPS, "avatargroupsrequest"); +} void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**) { @@ -615,36 +790,6 @@ void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); } -void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) -{ - LLPickData pick_data; - - // Extract the agent id and verify the message is for this - // client. - msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, pick_data.agent_id ); - msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_data.pick_id); - msg->getUUID(_PREHASH_Data, _PREHASH_CreatorID, pick_data.creator_id); - - // ** top_pick should be deleted, not being used anymore - angela - msg->getBOOL(_PREHASH_Data, _PREHASH_TopPick, pick_data.top_pick); - msg->getUUID(_PREHASH_Data, _PREHASH_ParcelID, pick_data.parcel_id); - msg->getString(_PREHASH_Data, _PREHASH_Name, pick_data.name); - msg->getString(_PREHASH_Data, _PREHASH_Desc, pick_data.desc); - msg->getUUID(_PREHASH_Data, _PREHASH_SnapshotID, pick_data.snapshot_id); - - msg->getString(_PREHASH_Data, _PREHASH_User, pick_data.user_name); - msg->getString(_PREHASH_Data, _PREHASH_OriginalName, pick_data.original_name); - msg->getString(_PREHASH_Data, _PREHASH_SimName, pick_data.sim_name); - msg->getVector3d(_PREHASH_Data, _PREHASH_PosGlobal, pick_data.pos_global); - - msg->getS32(_PREHASH_Data, _PREHASH_SortOrder, pick_data.sort_order); - msg->getBOOL(_PREHASH_Data, _PREHASH_Enabled, pick_data.enabled); - - LLAvatarPropertiesProcessor* self = getInstance(); - // don't need to remove pending request as we don't track pick info - self->notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO); -} - void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**) { LLAvatarGroups avatar_groups; @@ -670,44 +815,6 @@ void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, self->notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS); } -void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id, void* data, EAvatarProcessorType type) -{ - // Copy the map (because observers may delete themselves when updated?) - LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers; - - observer_multimap_t::iterator oi = observers.begin(); - observer_multimap_t::iterator end = observers.end(); - for (; oi != end; ++oi) - { - // only notify observers for the same agent, or if the observer - // didn't know the agent ID and passed a NULL id. - const LLUUID &agent_id = oi->first; - if (agent_id == id || agent_id.isNull()) - { - oi->second->processProperties(data, type); - } - } -} - -void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32 rights) -{ - if(!avatar_id.isNull()) - { - LLMessageSystem* msg = gMessageSystem; - - // setup message header - msg->newMessageFast(_PREHASH_GrantUserRights); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_Rights); - msg->addUUID(_PREHASH_AgentRelated, avatar_id); - msg->addS32(_PREHASH_RelatedRights, rights); - - gAgent.sendReliableMessage(); - } -} void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std::string notes) { @@ -729,181 +836,4 @@ void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std:: } } - -void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id ) -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessage(_PREHASH_PickDelete); - msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlock(_PREHASH_Data); - msg->addUUID(_PREHASH_PickID, pick_id); - gAgent.sendReliableMessage(); - - LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); - LLAgentPicksInfo::getInstance()->decrementNumberOfPicks(); -} - -void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_id) -{ - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage(_PREHASH_ClassifiedDelete); - - msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlock(_PREHASH_Data); - msg->addUUID(_PREHASH_ClassifiedID, classified_id); - - gAgent.sendReliableMessage(); -} - -void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const LLInterestsData* interests_data) -{ - if(!interests_data) - { - return; - } - - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage(_PREHASH_AvatarInterestsUpdate); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast( _PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast( _PREHASH_PropertiesData); - msg->addU32Fast( _PREHASH_WantToMask, interests_data->want_to_mask); - msg->addStringFast( _PREHASH_WantToText, interests_data->want_to_text); - msg->addU32Fast( _PREHASH_SkillsMask, interests_data->skills_mask); - msg->addStringFast( _PREHASH_SkillsText, interests_data->skills_text); - msg->addString( _PREHASH_LanguagesText, interests_data->languages_text); - - gAgent.sendReliableMessage(); -} - -void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick) -{ - if (!new_pick) return; - - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage(_PREHASH_PickInfoUpdate); - msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlock(_PREHASH_Data); - msg->addUUID(_PREHASH_PickID, new_pick->pick_id); - msg->addUUID(_PREHASH_CreatorID, new_pick->creator_id); - - //legacy var need to be deleted - msg->addBOOL(_PREHASH_TopPick, FALSE); - - // fills in on simulator if null - msg->addUUID(_PREHASH_ParcelID, new_pick->parcel_id); - msg->addString(_PREHASH_Name, new_pick->name); - msg->addString(_PREHASH_Desc, new_pick->desc); - msg->addUUID(_PREHASH_SnapshotID, new_pick->snapshot_id); - msg->addVector3d(_PREHASH_PosGlobal, new_pick->pos_global); - - // Only top picks have a sort order - msg->addS32(_PREHASH_SortOrder, 0); - - msg->addBOOL(_PREHASH_Enabled, new_pick->enabled); - gAgent.sendReliableMessage(); - - LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); -} - -void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data) -{ - if(!c_data) - { - return; - } - - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage(_PREHASH_ClassifiedInfoUpdate); - - msg->nextBlock(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlock(_PREHASH_Data); - msg->addUUID(_PREHASH_ClassifiedID, c_data->classified_id); - msg->addU32(_PREHASH_Category, c_data->category); - msg->addString(_PREHASH_Name, c_data->name); - msg->addString(_PREHASH_Desc, c_data->description); - msg->addUUID(_PREHASH_ParcelID, c_data->parcel_id); - msg->addU32(_PREHASH_ParentEstate, 0); - msg->addUUID(_PREHASH_SnapshotID, c_data->snapshot_id); - msg->addVector3d(_PREHASH_PosGlobal, c_data->pos_global); - msg->addU8(_PREHASH_ClassifiedFlags, c_data->flags); - msg->addS32(_PREHASH_PriceForListing, c_data->price_for_listing); - - gAgent.sendReliableMessage(); -} - -void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id) -{ - // Must ask for a pick based on the creator id because - // the pick database is distributed to the inventory cluster. JC - std::vector request_params; - request_params.push_back(creator_id.asString() ); - request_params.push_back(pick_id.asString() ); - send_generic_message("pickinforequest", request_params); -} - -void LLAvatarPropertiesProcessor::sendClassifiedInfoRequest(const LLUUID& classified_id) -{ - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage(_PREHASH_ClassifiedInfoRequest); - msg->nextBlock(_PREHASH_AgentData); - - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlock(_PREHASH_Data); - msg->addUUID(_PREHASH_ClassifiedID, classified_id); - - gAgent.sendReliableMessage(); -} - -bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) -{ - timestamp_map_t::key_type key = std::make_pair(avatar_id, type); - timestamp_map_t::iterator it = mRequestTimestamps.find(key); - - // Is this a new request? - if (it == mRequestTimestamps.end()) return false; - - // We found a request, check if it has timed out - U32 now = time(NULL); - const U32 REQUEST_EXPIRE_SECS = 5; - U32 expires = it->second + REQUEST_EXPIRE_SECS; - - // Request is still pending if it hasn't expired yet - // *NOTE: Expired requests will accumulate in this map, but they are rare, - // the data is small, and they will be updated if the same data is - // re-requested - return (now < expires); -} - -void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) -{ - timestamp_map_t::key_type key = std::make_pair(avatar_id, type); - U32 now = time(NULL); - // Add or update existing (expired) request - mRequestTimestamps[ key ] = now; -} - -void LLAvatarPropertiesProcessor::removePendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) -{ - timestamp_map_t::key_type key = std::make_pair(avatar_id, type); - mRequestTimestamps.erase(key); -} +// \ No newline at end of file diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index 6fead33cac..8d5e923050 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -40,6 +40,7 @@ const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided paymen const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. const U32 AVATAR_AGEVERIFIED = 0x1 << 5; // whether avatar has been age-verified +const U32 AVATAR_ONLINE_UNDEFINED = 0x1 << 31; // FIRE-32184: Online/Offline status not working for non-friends /* *TODO Vadim: This needs some refactoring: @@ -50,56 +51,77 @@ class LLMessageSystem; enum EAvatarProcessorType { - APT_PROPERTIES_LEGACY, // APT_PROPERTIES via udp request + APT_PROPERTIES_LEGACY, // APT_PROPERTIES via udp request (Truncates data!!!) APT_PROPERTIES, // APT_PROPERTIES via http request + // OpenSim APT_NOTES, APT_GROUPS, APT_PICKS, + // APT_PICK_INFO, APT_TEXTURES, - APT_INTERESTS_INFO, APT_CLASSIFIEDS, APT_CLASSIFIED_INFO }; -struct LLInterestsData +// legacy data is supposed to match AvatarPropertiesReply, +// but it is obsolete, fields like about_text will truncate +// data, if you need them, use AgenProfile cap. +// Todo: remove it once once icon ids get moved elsewhere, +// since AgentProfile is too large for bulk icon requests +struct LLAvatarLegacyData { - LLUUID agent_id; - LLUUID avatar_id; //target id - U32 want_to_mask; - std::string want_to_text; - U32 skills_mask; - std::string skills_text; - std::string languages_text; + LLUUID agent_id; + LLUUID avatar_id; //target id + LLUUID image_id; + LLUUID fl_image_id; + LLUUID partner_id; + std::string about_text; + std::string fl_about_text; + LLDate born_on; + std::string profile_url; + U8 caption_index; + std::string caption_text; + std::string customer_type; + U32 flags; }; struct LLAvatarData { - LLUUID agent_id; - LLUUID avatar_id; //target id - LLUUID image_id; - LLUUID fl_image_id; - LLUUID partner_id; - std::string about_text; - std::string fl_about_text; - LLDate born_on; - std::string profile_url; - U8 caption_index; - std::string caption_text; - std::string customer_type; - U32 flags; - bool hide_age; + LLUUID agent_id; + LLUUID avatar_id; //target id + LLUUID image_id; + LLUUID fl_image_id; + LLUUID partner_id; + std::string about_text; + std::string fl_about_text; + LLDate born_on; + std::string profile_url; + U8 caption_index; + std::string caption_text; + std::string customer_type; + U32 flags; + bool hide_age; + std::string notes; + + struct LLGroupData; + typedef std::list group_list_t; + group_list_t group_list; + + typedef std::pair pick_data_t; + typedef std::list< pick_data_t> picks_list_t; + picks_list_t picks_list; BOOL allow_publish; // UDP profiles }; -struct LLAvatarPicks +struct LLAvatarData::LLGroupData { - LLUUID agent_id; - LLUUID target_id; //target id - - typedef std::pair pick_data_t; - typedef std::list< pick_data_t> picks_list_t; - picks_list_t picks_list; + U64 group_powers; + BOOL accept_notices; + std::string group_title; + LLUUID group_id; + std::string group_name; + LLUUID group_insignia_id; }; struct LLPickData @@ -123,7 +145,17 @@ struct LLPickData //used only in write (update) requests LLUUID session_id; +}; +// OpenSim +struct LLAvatarPicks +{ + LLUUID agent_id; + LLUUID target_id; //target id + + typedef std::pair pick_data_t; + typedef std::list< pick_data_t> picks_list_t; + picks_list_t picks_list; }; struct LLAvatarNotes @@ -154,6 +186,7 @@ struct LLAvatarGroups LLUUID group_insignia_id; }; }; +// struct LLAvatarClassifieds { @@ -212,12 +245,16 @@ public: // Request various types of avatar data. Duplicate requests will be // suppressed while waiting for a response from the network. - void sendAvatarPropertiesRequest(const LLUUID& avatar_id, bool use_cap = false); + void sendAvatarPropertiesRequest(const LLUUID& avatar_id); + void sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id); + void sendAvatarTexturesRequest(const LLUUID& avatar_id); + void sendAvatarClassifiedsRequest(const LLUUID& avatar_id); + + // OpenSim void sendAvatarPicksRequest(const LLUUID& avatar_id); void sendAvatarNotesRequest(const LLUUID& avatar_id); void sendAvatarGroupsRequest(const LLUUID& avatar_id); - void sendAvatarTexturesRequest(const LLUUID& avatar_id); - void sendAvatarClassifiedsRequest(const LLUUID& avatar_id); + // // Duplicate pick info requests are not suppressed. void sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id); @@ -232,14 +269,12 @@ public: void sendFriendRights(const LLUUID& avatar_id, S32 rights); + // OpenSim void sendNotes(const LLUUID& avatar_id, const std::string notes); - void sendPickDelete(const LLUUID& pick_id); void sendClassifiedDelete(const LLUUID& classified_id); - void sendInterestsInfoUpdate(const LLInterestsData* interests_data); - // Returns translated, human readable string for account type, such // as "Resident" or "Linden Employee". Used for profiles, inspectors. static std::string accountType(const LLAvatarData* avatar_data); @@ -251,22 +286,20 @@ public: static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data); - static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id, EAvatarProcessorType type); + static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type); - static void processAvatarPropertiesReply(LLMessageSystem* msg, void**); - - static void processAvatarInterestsReply(LLMessageSystem* msg, void**); + // Processing of UDP variant of properties, truncates certain fields! + static void processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**); static void processAvatarClassifiedsReply(LLMessageSystem* msg, void**); static void processClassifiedInfoReply(LLMessageSystem* msg, void**); + // OpenSim static void processAvatarGroupsReply(LLMessageSystem* msg, void**); - static void processAvatarNotesReply(LLMessageSystem* msg, void**); - static void processAvatarPicksReply(LLMessageSystem* msg, void**); - + // static void processPickInfoReply(LLMessageSystem* msg, void**); protected: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index b33abfbe8e..5dc292fac7 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -656,6 +656,9 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF switch(filter) { case FFLOAD_ALL: + case FFLOAD_EXE: + allowedv->push_back("app"); + allowedv->push_back("exe"); allowedv->push_back("wav"); allowedv->push_back("bvh"); allowedv->push_back("anim"); @@ -679,9 +682,6 @@ std::unique_ptr> LLFilePicker::navOpenFilterProc(ELoadF allowedv->push_back("tpic"); allowedv->push_back("png"); break; - case FFLOAD_EXE: - allowedv->push_back("app"); - allowedv->push_back("exe"); break; case FFLOAD_WAV: allowedv->push_back("wav"); diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index 39e6b3c7f8..4363294787 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -404,7 +404,13 @@ LLFetchAvatarPaymentInfo::LLFetchAvatarPaymentInfo(bool has_target, const std::s processor->addObserver(mAvatarID, this); // send a request (duplicates will be suppressed inside the avatar // properties processor) - processor->sendAvatarPropertiesRequest(mAvatarID); + // OpenSim + //processor->sendAvatarPropertiesRequest(mAvatarID); + if (!gAgent.getRegionCapability("AgentProfile").empty()) + processor->sendAvatarPropertiesRequest(mAvatarID); + else + processor->sendAvatarLegacyPropertiesRequest(mAvatarID); + // } LLFetchAvatarPaymentInfo::~LLFetchAvatarPaymentInfo() @@ -414,7 +420,7 @@ LLFetchAvatarPaymentInfo::~LLFetchAvatarPaymentInfo() void LLFetchAvatarPaymentInfo::processProperties(void* data, EAvatarProcessorType type) { - if (data && type == APT_PROPERTIES_LEGACY) + if (data && (type == APT_PROPERTIES || type == APT_PROPERTIES_LEGACY)) { LLAvatarData* avatar_data = static_cast(data); LLFloaterBuyCurrency::handleBuyCurrency(LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(avatar_data), mHasTarget, mName, mPrice); diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index f88e8741cf..6aba2e7c61 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -327,6 +327,13 @@ void LLFloaterJoystick::refresh() initFromSettings(); } +bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD& value, void* userdata) +{ + LLFloaterJoystick * floater = (LLFloaterJoystick*)userdata; + floater->mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); + return false; // keep searching +} + void LLFloaterJoystick::addDevice(std::string &name, LLSD& value) { mJoysticksCombo->add(name, value, ADD_BOTTOM, 1); @@ -341,19 +348,21 @@ void LLFloaterJoystick::refreshListOfDevices() mHasDeviceList = false; + void* win_calback = nullptr; // di8_devices_callback callback is immediate and happens in scope of getInputDevices() #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib U32 device_type = DI8DEVCLASS_GAMECTRL; - void* callback = &di8_list_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one + win_calback = di8_list_devices_callback; +#elif LL_DARWIN + U32 device_type = 0; +#else + // On MAC it is possible to specify product + // and manufacturer in NDOF_Device for + // ndof_init_first to pick specific device U32 device_type = 0; - void* callback = NULL; #endif - if (gViewerWindow->getWindow()->getInputDevices(device_type, callback, this)) + if (gViewerWindow->getWindow()->getInputDevices(device_type, addDeviceCallback, win_calback, this)) { mHasDeviceList = true; } @@ -495,10 +504,11 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) joystick->toggleFlycam(); } } - - std::string device_id = LLViewerJoystick::getInstance()->getDeviceUUIDString(); - gSavedSettings.setString("JoystickDeviceUUID", device_id); - LL_DEBUGS("Joystick") << "Selected " << device_id << " as joystick." << LL_ENDL; + + LLViewerJoystick::getInstance()->saveDeviceIdToSettings(); + + std::string device_string = LLViewerJoystick::getInstance()->getDeviceUUIDString(); + LL_DEBUGS("Joystick") << "Selected " << device_string << " as joystick." << LL_ENDL; self->refreshListOfDevices(); diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index e4fc7d92c5..f7bd579cca 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -50,6 +50,7 @@ public: virtual void draw(); static void setSNDefaults(); + static bool addDeviceCallback(std::string &name, LLSD& value, void* userdata); void addDevice(std::string &name, LLSD& value); protected: diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index bbd7b6e227..636819469c 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -557,7 +557,7 @@ void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType t { if ( APT_PROPERTIES_LEGACY == type ) { - const LLAvatarData* pAvatarData = static_cast( pData ); + const LLAvatarLegacyData* pAvatarData = static_cast( pData ); if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) { mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH); @@ -1108,7 +1108,7 @@ void LLFloaterPreference::onOpen(const LLSD& key) (gAgent.isMature() || gAgent.isGodlike()); LLComboBox* maturity_combo = getChild("maturity_desired_combobox"); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() ); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest( gAgent.getID() ); if (can_choose_maturity) { // if they're not adult or a god, they shouldn't see the adult selection, so delete it diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index e228a7ae63..b648d34530 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -196,9 +196,11 @@ public: // send a request (duplicates will be suppressed inside the avatar // properties processor) // OpenSim - //processor->sendAvatarPropertiesRequest(mAvatarID, true); - const bool use_cap = LLGridManager::instance().isInSecondLife() ? true : !gAgent.getRegionCapability("AgentProfile").empty(); - processor->sendAvatarPropertiesRequest(mAvatarID, use_cap); + //processor->sendAvatarPropertiesRequest(mAvatarID); + if (LLGridManager::instance().isInSecondLife() || !gAgent.getRegionCapability("AgentProfile").empty()) + processor->sendAvatarPropertiesRequest(mAvatarID); + else + processor->sendAvatarLegacyPropertiesRequest(mAvatarID); // } diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index f396fc74d2..24ca55c9b5 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -210,3 +210,16 @@ void LLPanelProfilePropertiesProcessorTab::setAvatarId(const LLUUID & avatar_id) LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); } } + +void LLPanelProfilePropertiesProcessorTab::updateData() +{ + LLUUID avatar_id = getAvatarId(); + // OpenSim + //if (!getStarted() && avatar_id.notNull()) + if (!getStarted() && avatar_id.notNull() && !gAgent.getRegionCapability("AgentProfile").empty()) + // + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId()); + } +} diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 572e1eb029..1106c44734 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -97,12 +97,12 @@ public: /** * Sends update data request to server. */ - virtual void updateData() {}; + virtual void updateData(){}; /** * Clears panel data if viewing avatar info for first time and sends update data request. */ - virtual void onOpen(const LLSD& key); + virtual void onOpen(const LLSD& key) override; /** * Clears all data received from server. @@ -160,12 +160,14 @@ public: LLPanelProfilePropertiesProcessorTab(); ~LLPanelProfilePropertiesProcessorTab(); - /*virtual*/ void setAvatarId(const LLUUID& avatar_id); + void setAvatarId(const LLUUID& avatar_id) override; + + void updateData() override; /** * Processes data received from server via LLAvatarPropertiesObserver. */ - virtual void processProperties(void* data, EAvatarProcessorType type) = 0; + virtual void processProperties(void* data, EAvatarProcessorType type) override = 0; }; #endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 183000ceac..e926ed2b3c 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -104,6 +104,11 @@ LLPanelClassifiedInfo::LLPanelClassifiedInfo() LLPanelClassifiedInfo::~LLPanelClassifiedInfo() { sAllPanels.remove(this); + + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } } BOOL LLPanelClassifiedInfo::postBuild() diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index b1541fca64..da105746d1 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -103,192 +103,8 @@ static const std::string PANEL_PROFILE_VIEW = "panel_profile_view"; static const std::string PROFILE_PROPERTIES_CAP = "AgentProfile"; static const std::string PROFILE_IMAGE_UPLOAD_CAP = "UploadAgentProfileImage"; -// FIRE-32184: Online/Offline status not working for non-friends -const U32 AVATAR_ONLINE_UNDEFINED = 0x1 << 31; - ////////////////////////////////////////////////////////////////////////// -void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("request_avatar_properties_coro", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLCore::HttpHeaders::ptr_t httpHeaders; - - LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - httpOpts->setFollowRedirects(true); - - std::string finalUrl = cap_url + "/" + agent_id.asString(); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Result: " << httpResults << LL_ENDL; - - if (!status - || !result.has("id") - || agent_id != result["id"].asUUID()) - { - LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL; - return; - } - - LLFloater* floater_profile = LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id)); - if (!floater_profile) - { - // floater is dead, so panels are dead as well - return; - } - - LLPanel *panel = floater_profile->findChild(PANEL_PROFILE_VIEW, TRUE); - LLPanelProfile *panel_profile = dynamic_cast(panel); - if (!panel_profile) - { - LL_WARNS() << PANEL_PROFILE_VIEW << " not found" << LL_ENDL; - return; - } - - // Avatar Data - LLAvatarData *avatar_data = &panel_profile->mAvatarData; - std::string birth_date; - - avatar_data->agent_id = agent_id; - avatar_data->avatar_id = agent_id; - avatar_data->image_id = result["sl_image_id"].asUUID(); - avatar_data->fl_image_id = result["fl_image_id"].asUUID(); - avatar_data->partner_id = result["partner_id"].asUUID(); - avatar_data->about_text = result["sl_about_text"].asString(); - avatar_data->fl_about_text = result["fl_about_text"].asString(); - avatar_data->born_on = result["member_since"].asDate(); - avatar_data->profile_url = getProfileURL(agent_id.asString()); - avatar_data->customer_type = result["customer_type"].asString(); - - avatar_data->flags = 0; - - // FIRE-32184: Online/Offline status not working for non-friends - // if (result["online"].asBoolean()) - if (result["online"].isUndefined()) - { - avatar_data->flags |= AVATAR_ONLINE_UNDEFINED; - } - else if (result["online"].asBoolean()) - // - { - avatar_data->flags |= AVATAR_ONLINE; - } - if (result["allow_publish"].asBoolean()) - { - avatar_data->flags |= AVATAR_ALLOW_PUBLISH; - } - if (result["identified"].asBoolean()) - { - avatar_data->flags |= AVATAR_IDENTIFIED; - } - if (result["transacted"].asBoolean()) - { - avatar_data->flags |= AVATAR_TRANSACTED; - } - - avatar_data->caption_index = 0; - if (result.has("charter_member")) // won't be present if "caption" is set - { - avatar_data->caption_index = result["charter_member"].asInteger(); - } - else if (result.has("caption")) - { - avatar_data->caption_text = result["caption"].asString(); - } - - // TODO: SL-20163 Remove the "has" check when SRV-684 is done - // and the field "hide_age" is included to the http response - avatar_data->hide_age = result.has("hide_age") ? - result["hide_age"].asBoolean() : // Server option value provided by resident - !panel_profile->getSelfProfile(); // Fallback temporary value (to be removed) - - panel = floater_profile->findChild(PANEL_SECONDLIFE, TRUE); - LLPanelProfileSecondLife *panel_sl = dynamic_cast(panel); - if (panel_sl) - { - panel_sl->processProfileProperties(avatar_data); - } - - panel = floater_profile->findChild(PANEL_WEB, TRUE); - LLPanelProfileWeb *panel_web = dynamic_cast(panel); - if (panel_web) - { - panel_web->setLoaded(); - } - - panel = floater_profile->findChild(PANEL_FIRSTLIFE, TRUE); - LLPanelProfileFirstLife *panel_first = dynamic_cast(panel); - if (panel_first) - { - panel_first->processProperties(avatar_data); - } - - // Picks - LLSD picks_array = result["picks"]; - LLAvatarPicks avatar_picks; - avatar_picks.agent_id = agent_id; // Not in use? - avatar_picks.target_id = agent_id; - - for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it) - { - const LLSD& pick_data = *it; - avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); - } - - panel = floater_profile->findChild(PANEL_PICKS, TRUE); - LLPanelProfilePicks *panel_picks = dynamic_cast(panel); - if (panel_picks) - { - // Refresh pick limit before processing - LLAgentPicksInfo::getInstance()->onServerRespond(&avatar_picks); - panel_picks->processProperties(&avatar_picks); - } - - // Groups - LLSD groups_array = result["groups"]; - LLAvatarGroups avatar_groups; - avatar_groups.agent_id = agent_id; // Not in use? - avatar_groups.avatar_id = agent_id; // target_id - - for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it) - { - const LLSD& group_info = *it; - LLAvatarGroups::LLGroupData group_data; - group_data.group_powers = 0; // Not in use? - group_data.group_title = group_info["name"].asString(); // Missing data, not in use? - group_data.group_id = group_info["id"].asUUID(); - group_data.group_name = group_info["name"].asString(); - group_data.group_insignia_id = group_info["image_id"].asUUID(); - - avatar_groups.group_list.push_back(group_data); - } - - if (panel_sl) - { - panel_sl->processGroupProperties(&avatar_groups); - } - - // Notes - LLAvatarNotes avatar_notes; - - avatar_notes.agent_id = agent_id; - avatar_notes.target_id = agent_id; - avatar_notes.notes = result["notes"].asString(); - - panel = floater_profile->findChild(PANEL_NOTES, TRUE); - LLPanelProfileNotes *panel_notes = dynamic_cast(panel); - if (panel_notes) - { - panel_notes->processProperties(&avatar_notes); - } -} - LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::string path_to_image, LLHandle *handle) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -885,7 +701,7 @@ void LLFloaterProfilePermissions::onCancel() // LLPanelProfileSecondLife LLPanelProfileSecondLife::LLPanelProfileSecondLife() - : LLPanelProfilePropertiesProcessorTab() // alter ancestry to re-enable UDP + : LLPanelProfilePropertiesProcessorTab() , mAvatarNameCacheConnection() , mHasUnsavedDescriptionChanges(false) , mWaitingForImageUpload(false) @@ -1004,11 +820,11 @@ BOOL LLPanelProfileSecondLife::postBuild() } // FIRE-32184: Online/Offline status not working for non-friends -void LLPanelProfileSecondLife::onAvatarProperties(const LLAvatarData* d) +void LLPanelProfileSecondLife::onAvatarProperties(const LLAvatarData* data) { // only update the "unknown" status if they are showing as online, otherwise // we still don't know their true status - if (d->agent_id == gAgentID && d->flags & AVATAR_ONLINE) + if (data->agent_id == gAgentID && data->flags & AVATAR_ONLINE) { processOnlineStatus(false, true, true); } @@ -1102,34 +918,26 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key) mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); } +// restore UDP profiles for opensim that does not support the cap void LLPanelProfileSecondLife::updateData() { - LLUUID avatar_id = getAvatarId(); - if (!getStarted() && avatar_id.notNull()) - { - setIsLoading(); - - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("requestAgentUserInfoCoro", - [cap_url, avatar_id]() { request_avatar_properties_coro(cap_url, avatar_id); }); - } - else - { - // restore UDP profiles for opensim that does not support the cap #ifdef OPENSIM - if (LLGridManager::instance().isInOpenSim() && !(getSelfProfile() /* TODO(Beq):No longer neeed? && !getEmbedded()*/)) - { - LLAvatarPropertiesProcessor::getInstance()->sendAvatarGroupsRequest(avatar_id); - } - else -#endif - // - LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL; + if (LLGridManager::instance().isInOpenSim() && gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) + { + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull() && gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty() && !getSelfProfile()) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarGroupsRequest(avatar_id); } } + else +#endif + { + LLPanelProfilePropertiesProcessorTab::updateData(); + } } +// void LLPanelProfileSecondLife::refreshName() { @@ -1153,34 +961,6 @@ void LLPanelProfileSecondLife::apply(LLAvatarData* data) } #endif } - -void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type) -{ - // discard UDP replies for profile data if profile capability is available - // otherwise we will truncate profile descriptions to the old UDP limits - if (!gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) - { - return; - } - - if (APT_PROPERTIES_LEGACY == type) - { - const LLAvatarData* avatar_data = static_cast(data); - if(avatar_data && getAvatarId() == avatar_data->avatar_id) - { - processProfileProperties(avatar_data); - setLoaded(); - } - } - else if (APT_GROUPS == type) - { - LLAvatarGroups* avatar_groups = static_cast(data); - if(avatar_groups && getAvatarId() == avatar_groups->avatar_id) - { - processGroupProperties(avatar_groups); - } - } -} // void LLPanelProfileSecondLife::resetData() @@ -1251,6 +1031,44 @@ void LLPanelProfileSecondLife::resetData() // } +void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProfileProperties(avatar_data); + } + } + + // Restore UDP profiles + // discard UDP replies for profile data if profile capability is available + // otherwise we will truncate profile descriptions to the old UDP limits + if (!gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) + { + return; + } + + if (APT_PROPERTIES_LEGACY == type) + { + const LLAvatarData* avatar_data = static_cast(data); + if(avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProfileProperties(avatar_data); + } + } + else if (APT_GROUPS == type) + { + LLAvatarGroups* avatar_groups = static_cast(data); + if(avatar_groups && getAvatarId() == avatar_groups->avatar_id) + { + processGroupProperties(avatar_groups); + } + } + // +} + void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) { const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); @@ -1278,6 +1096,19 @@ void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avat fillAccountStatus(avatar_data); + if (!gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) { // + LLAvatarData::group_list_t::const_iterator it = avatar_data->group_list.begin(); + const LLAvatarData::group_list_t::const_iterator it_end = avatar_data->group_list.end(); + + for (; it_end != it; ++it) + { + LLAvatarData::LLGroupData group_data = *it; + mGroups[group_data.group_name] = group_data.group_id; + } + + mGroupList->setGroups(mGroups); + } // + // Restore UDP profiles #ifdef OPENSIM if (LLGridManager::instance().isInOpenSim()) @@ -1307,6 +1138,7 @@ void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avat updateButtons(); } +// OpenSim void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups) { LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin(); @@ -1320,6 +1152,7 @@ void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avat mGroupList->setGroups(mGroups); } +// void LLPanelProfileSecondLife::openGroupProfile() { @@ -1690,14 +1523,15 @@ void LLPanelProfileSecondLife::fillAgeData(const LLAvatarData* avatar_data) // Fix LL UI/UX design accident //// Date from server comes already converted to stl timezone, //// so display it as an UTC + 0 - //std::string name_and_date = getString(avatar_data->hide_age ? "date_format_short" : "date_format_full"); + //bool hide_age = avatar_data->hide_age && !getSelfProfile(); + //std::string name_and_date = getString(hide_age ? "date_format_short" : "date_format_full"); //LLSD args_name; //args_name["datetime"] = (S32)avatar_data->born_on.secondsSinceEpoch(); //LLStringUtil::format(name_and_date, args_name); //getChild("sl_birth_date")->setValue(name_and_date); //LLUICtrl* userAgeCtrl = getChild("user_age"); - //if (avatar_data->hide_age) + //if (hide_age) //{ // userAgeCtrl->setVisible(FALSE); //} @@ -1831,7 +1665,7 @@ void LLPanelProfileSecondLife::setAvatarId(const LLUUID& avatar_id) LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); } - LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id); // Change ancestry to restore UDP profiles + LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id); if (LLAvatarActions::isFriend(getAvatarId())) { @@ -1874,7 +1708,7 @@ void LLPanelProfileSecondLife::processOnlineStatus(bool is_friend, bool show_onl mPropertiesObserver.mPanelProfile = this; mPropertiesObserver.mRequester = gAgentID; LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), &mPropertiesObserver); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId()); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest(getAvatarId()); return; } @@ -2771,6 +2605,8 @@ void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e LLStringUtil::format_map_t args; args["[TIME]"] = llformat("%.2f", mPerformanceTimer.getElapsedTimeF32()); childSetValue("status_text", LLSD( getString("LoadTime", args)) ); + + setLoaded(); } break; @@ -2786,7 +2622,7 @@ void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e ////////////////////////////////////////////////////////////////////////// LLPanelProfileFirstLife::LLPanelProfileFirstLife() - : LLPanelProfilePropertiesProcessorTab() // alter ancestry to re-enable UDP + : LLPanelProfilePropertiesProcessorTab() , mHasUnsavedChanges(false) { } @@ -3058,16 +2894,8 @@ void LLPanelProfileFirstLife::onDiscardDescriptionChanges() setDescriptionText(mCurrentDescription); } -// Restore UDP profiles void LLPanelProfileFirstLife::processProperties(void * data, EAvatarProcessorType type) { - // discard UDP replies for profile data if profile capability is available - // otherwise we will truncate profile first life descriptions to the old UDP limits - if (!gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) - { - return; - } - if (APT_PROPERTIES == type) { const LLAvatarData* avatar_data = static_cast(data); @@ -3076,8 +2904,17 @@ void LLPanelProfileFirstLife::processProperties(void * data, EAvatarProcessorTyp processProperties(avatar_data); } } + // Restore UDP profiles + else if (gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty() && APT_PROPERTIES_LEGACY == type) + { + const LLAvatarData* avatar_data = static_cast(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProperties(avatar_data); + } + } + // } -// void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data) { @@ -3152,7 +2989,7 @@ void LLPanelProfileFirstLife::setLoaded() ////////////////////////////////////////////////////////////////////////// LLPanelProfileNotes::LLPanelProfileNotes() -: LLPanelProfilePropertiesProcessorTab() // alter ancestry to re-enable UDP +: LLPanelProfilePropertiesProcessorTab() , mHasUnsavedChanges(false) { @@ -3162,29 +2999,26 @@ LLPanelProfileNotes::~LLPanelProfileNotes() { } +// Restore UDP profiles void LLPanelProfileNotes::updateData() { - LLUUID avatar_id = getAvatarId(); - if (!getStarted() && avatar_id.notNull()) - { - setIsLoading(); - - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("requestAgentUserInfoCoro", - [cap_url, avatar_id]() { request_avatar_properties_coro(cap_url, avatar_id); }); - } -// Restore UDO profiles #ifdef OPENSIM - else if(LLGridManager::instance().isInOpenSim()) + if (LLGridManager::instance().isInOpenSim() && gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) + { + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull() && gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty() && !getSelfProfile()) { + setIsLoading(); LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(avatar_id); } + } + else #endif -// + { + LLPanelProfilePropertiesProcessorTab::updateData(); } } +// void LLPanelProfileNotes::commitUnsavedChanges() { @@ -3267,32 +3101,37 @@ void LLPanelProfileNotes::onDiscardNotesChanges() setNotesText(mCurrentNotes); } -void LLPanelProfileNotes::processProperties(LLAvatarNotes* avatar_notes) +void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType type) { - setNotesText(avatar_notes->notes); + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProperties(avatar_data); + } + } + + // Restore UDP profiles + else if (gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty() && APT_NOTES == type) + { + LLAvatarNotes* avatar_notes = static_cast(data); + if (avatar_notes && getAvatarId() == avatar_notes->target_id) + { + LLAvatarData avatardata; + avatardata.notes = avatar_notes->notes; + processProperties(&avatardata); + } + } + // +} + +void LLPanelProfileNotes::processProperties(const LLAvatarData* avatar_data) +{ + setNotesText(avatar_data->notes); mNotesEditor->setEnabled(TRUE); setLoaded(); } -// Restore UDP profiles -void LLPanelProfileNotes::processProperties(void * data, EAvatarProcessorType type) -{ - // discard UDP replies for profile data if profile capability is available - // otherwise we will truncate profile notes to the old UDP limits - if (!gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) - { - return; - } - - if (APT_NOTES == type) - { - LLAvatarNotes* avatar_notes = static_cast(data); - if (avatar_notes && getAvatarId() == avatar_notes->target_id) - { - processProperties(avatar_notes); - } - } -} -// void LLPanelProfileNotes::resetData() { @@ -3300,14 +3139,6 @@ void LLPanelProfileNotes::resetData() setNotesText(std::string()); } -void LLPanelProfileNotes::setAvatarId(const LLUUID& avatar_id) -{ - if (avatar_id.notNull()) - { - LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id); // alter ancestry to re-enable UDP - } -} - ////////////////////////////////////////////////////////////////////////// // LLPanelProfile @@ -3396,17 +3227,17 @@ void LLPanelProfile::updateData() mPanelFirstlife->setIsLoading(); mPanelNotes->setIsLoading(); } // restore udp profiles - std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); - if (!cap_url.empty()) - { - LLCoros::instance().launch("requestAgentUserInfoCoro", - [cap_url, avatar_id]() { request_avatar_properties_coro(cap_url, avatar_id); }); - } + // Restore UDP profiles + //LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId()); + if (!gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty()) + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId()); + } #ifdef OPENSIM else if (LLGridManager::instance().isInOpenSim()) { - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest(avatar_id); } #endif // diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 884ddfc37b..26b73b88f6 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -112,8 +112,7 @@ public: * Sends update data request to server. */ void apply(LLAvatarData* data); - void processProperties(void* data, EAvatarProcessorType type) override; - void updateData() override; + void updateData() override; // OpenSim void refreshName(); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); @@ -124,10 +123,10 @@ public: bool hasUnsavedChanges() override; void commitUnsavedChanges() override; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); + void processProperties(void* data, EAvatarProcessorType type) override; // FIRE-32184: Online/Offline status not working for non-friends - void onAvatarProperties(const LLAvatarData* d); + void onAvatarProperties(const LLAvatarData* data); protected: /** @@ -138,6 +137,7 @@ protected: /** * Processes group related data received from server. */ + // OpenSim void processGroupProperties(const LLAvatarGroups* avatar_groups); /** @@ -307,8 +307,6 @@ public: void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - protected: void onCommitLoad(LLUICtrl* ctrl); @@ -337,8 +335,8 @@ public: BOOL postBuild() override; + void processProperties(void* data, EAvatarProcessorType type) override; void processProperties(const LLAvatarData* avatar_data); - void processProperties(void * data, EAvatarProcessorType type) override; void apply(LLAvatarData* data); void resetData() override; @@ -348,8 +346,6 @@ public: bool hasUnsavedChanges() override { return mHasUnsavedChanges; } void commitUnsavedChanges() override; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - protected: void setLoaded() override; @@ -391,16 +387,15 @@ public: LLPanelProfileNotes(); /*virtual*/ ~LLPanelProfileNotes(); - void setAvatarId(const LLUUID& avatar_id) override; - void onOpen(const LLSD& key) override; BOOL postBuild() override; - void processProperties(LLAvatarNotes* avatar_notes); - void processProperties(void * data, EAvatarProcessorType type) override; + void processProperties(void* data, EAvatarProcessorType type) override; + void processProperties(const LLAvatarData* avatar_data); void resetData() override; + // OpenSim void updateData() override; bool hasUnsavedChanges() override { return mHasUnsavedChanges; } @@ -452,8 +447,6 @@ public: LLAvatarData getAvatarData() { return mAvatarData; }; void setAvatarData(const LLAvatarData* avatar_data){ mAvatarData = *avatar_data; }; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - private: void onTabChange(); @@ -465,6 +458,7 @@ private: LLPanelProfileNotes* mPanelNotes; LLTabContainer* mTabContainer; + // OpenSim // Todo: due to server taking minutes to update this needs a more long term storage // to reuse recently saved values if user opens floater again // Storage implementation depends onto how a cap will be implemented, if cap will be diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 8b0654c79e..165ed1ae5f 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -307,17 +307,33 @@ void LLPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLS void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type) { - if (APT_PICKS == type) + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_picks = static_cast(data); + if (avatar_picks && getAvatarId() == avatar_picks->avatar_id) + { + if (getSelfProfile()) + { + LLAgentPicksInfo::getInstance()->onServerRespond(avatar_picks); + } + processProperties(avatar_picks); + } + } + // OpenSim + else if (APT_PICKS == type) { LLAvatarPicks* avatar_picks = static_cast(data); if (avatar_picks && getAvatarId() == avatar_picks->target_id) { - processProperties(avatar_picks); + LLAvatarData avatardata; + avatardata.picks_list = avatar_picks->picks_list; + processProperties(&avatardata); } } + // } -void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) +void LLPanelProfilePicks::processProperties(const LLAvatarData* avatar_picks) { LLUUID selected_id = mPickToSelectOnLoad; bool has_selection = false; @@ -335,7 +351,7 @@ void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) mTabContainer->deleteAllTabs(); - LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); + LLAvatarData::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); for (; avatar_picks->picks_list.end() != it; ++it) { LLUUID pick_id = it->first; @@ -442,7 +458,13 @@ void LLPanelProfilePicks::updateData() { setIsLoading(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id); + // OpenSim + //LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id); + if (!gAgent.getRegionCapability("AgentProfile").empty()) + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id); + else + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id); + // } if (!getIsLoaded()) { diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index 34407d37d5..8e569d7f16 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -60,7 +60,7 @@ public: void selectPick(const LLUUID& pick_id); void processProperties(void* data, EAvatarProcessorType type) override; - void processProperties(const LLAvatarPicks* avatar_picks); + void processProperties(const LLAvatarData* avatar_picks); void resetData() override; @@ -79,8 +79,6 @@ public: bool hasUnsavedChanges() override; void commitUnsavedChanges() override; - friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); - private: void onClickNewBtn(); void onClickDelete(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index f71f388384..e4cc139788 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3562,18 +3562,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) LLViewerParcelMgr::processParcelDwellReply); msg->setHandlerFunc("AvatarPropertiesReply", - &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); - msg->setHandlerFunc("AvatarInterestsReply", - &LLAvatarPropertiesProcessor::processAvatarInterestsReply); - msg->setHandlerFunc("AvatarGroupsReply", - &LLAvatarPropertiesProcessor::processAvatarGroupsReply); - // ratings deprecated - //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, - // LLPanelAvatar::processAvatarStatisticsReply); - msg->setHandlerFunc("AvatarNotesReply", - &LLAvatarPropertiesProcessor::processAvatarNotesReply); - msg->setHandlerFunc("AvatarPicksReply", - &LLAvatarPropertiesProcessor::processAvatarPicksReply); + &LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply); msg->setHandlerFunc("AvatarClassifiedReply", &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index 67f3f75616..104e6db57b 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -234,8 +234,18 @@ std::string string_from_guid(const GUID &guid) return res; } +#elif LL_DARWIN + +bool macos_devices_callback(std::string &product_name, LLSD &data, void* userdata) +{ + std::string product = data["product"].asString(); + + return LLViewerJoystick::getInstance()->initDevice(nullptr, product, data); +} + #endif + // ----------------------------------------------------------------------------- void LLViewerJoystick::updateEnabled(bool autoenable) { @@ -384,25 +394,48 @@ void LLViewerJoystick::init(bool autoenable) { if (mNdofDev) { + U32 device_type = 0; + void* win_callback = nullptr; + std::function osx_callback; // di8_devices_callback callback is immediate and happens in scope of getInputDevices() #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib - U32 device_type = DI8DEVCLASS_GAMECTRL; - void* callback = &di8_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one - U32 device_type = 0; - void* callback = NULL; -#endif - if (!gViewerWindow->getWindow()->getInputDevices(device_type, callback, NULL)) + device_type = DI8DEVCLASS_GAMECTRL; + win_callback = &di8_devices_callback; +#elif LL_DARWIN + osx_callback = macos_devices_callback; + + if (mLastDeviceUUID.isMap()) { - LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one - mLastDeviceUUID = LLSD(); - void *preffered_device = NULL; - initDevice(preffered_device); + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + + if (ndof_init_first(mNdofDev, nullptr)) + { + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + // No device found + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; + } + } +#endif + if (mDriverState != JDS_INITIALIZED) + { + if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices, init first suitable one + mLastDeviceUUID = LLSD(); + void *preffered_device = NULL; + initDevice(preffered_device); + } } if (mDriverState == JDS_INITIALIZING) @@ -457,27 +490,49 @@ void LLViewerJoystick::initDevice(LLSD &guid) { #if LIB_NDOF mLastDeviceUUID = guid; - + U32 device_type = 0; + void* win_callback = nullptr; + std::function osx_callback; + mDriverState = JDS_INITIALIZING; + #if LL_WINDOWS && !LL_MESA_HEADLESS // space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib - U32 device_type = DI8DEVCLASS_GAMECTRL; - void* callback = &di8_devices_callback; -#else - // MAC doesn't support device search yet - // On MAC there is an ndof_idsearch and it is possible to specify product - // and manufacturer in NDOF_Device for ndof_init_first to pick specific one - U32 device_type = 0; - void* callback = NULL; + device_type = DI8DEVCLASS_GAMECTRL; + win_callback = &di8_devices_callback; +#elif LL_DARWIN + osx_callback = macos_devices_callback; + if (mLastDeviceUUID.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + + if (ndof_init_first(mNdofDev, nullptr)) + { + mDriverState = JDS_INITIALIZING; + // Saved device no longer exist + // Np other device present + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + } + else + { + mDriverState = JDS_INITIALIZED; + } + } #endif - mDriverState = JDS_INITIALIZING; - if (!gViewerWindow->getWindow()->getInputDevices(device_type, callback, NULL)) + if (mDriverState != JDS_INITIALIZED) { - LL_INFOS("Joystick") << "Failed to gather devices from window. Falling back to ndof's init" << LL_ENDL; - // Failed to gather devices from windows, init first suitable one - void *preffered_device = NULL; - mLastDeviceUUID = LLSD(); - initDevice(preffered_device); + if (!gViewerWindow->getWindow()->getInputDevices(device_type, osx_callback, win_callback, NULL)) + { + LL_INFOS("Joystick") << "Failed to gather input devices. Falling back to ndof's init" << LL_ENDL; + // Failed to gather devices from window, init first suitable one + void *preffered_device = NULL; + mLastDeviceUUID = LLSD(); + initDevice(preffered_device); + } } if (mDriverState == JDS_INITIALIZING) @@ -488,11 +543,26 @@ void LLViewerJoystick::initDevice(LLSD &guid) #endif } -void LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) +bool LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid) { #if LIB_NDOF mLastDeviceUUID = guid; - + +#if LL_DARWIN + if (guid.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + + strncpy(mNdofDev->manufacturer, manufacturer.c_str(), sizeof(mNdofDev->manufacturer)); + strncpy(mNdofDev->product, product.c_str(), sizeof(mNdofDev->product)); + } + else + { + mNdofDev->product[0] = '\0'; + mNdofDev->manufacturer[0] = '\0'; + } +#else #ifdef LL_LINUX #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" @@ -504,12 +574,15 @@ void LLViewerJoystick::initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8 mNdofDev->product[ sizeof(mNdofDev->product)-1 ] = 0; mNdofDev->manufacturer[0] = '\0'; +#endif - initDevice(preffered_device); + return initDevice(preffered_device); +#else + return false; #endif } -void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) +bool LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE8* */) { #if LIB_NDOF // Different joysticks will return different ranges of raw values. @@ -539,8 +612,10 @@ void LLViewerJoystick::initDevice(void * preffered_device /* LPDIRECTINPUTDEVICE else { mDriverState = JDS_INITIALIZED; + return true; } #endif + return false; } // ----------------------------------------------------------------------------- @@ -1378,6 +1453,8 @@ bool LLViewerJoystick::isDeviceUUIDSet() #if LL_WINDOWS && !LL_MESA_HEADLESS // for ease of comparison and to dial less with platform specific variables, we store id as LLSD binary return mLastDeviceUUID.isBinary(); +#elif LL_DARWIN + return mLastDeviceUUID.isMap(); #else return false; #endif @@ -1404,19 +1481,48 @@ std::string LLViewerJoystick::getDeviceUUIDString() { return std::string(); } +#elif LL_DARWIN + if (mLastDeviceUUID.isMap()) + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + return manufacturer + ":" + product; + } + else + { + return std::string(); + } #else return std::string(); - // return mLastDeviceUUID; +#endif +} + +void LLViewerJoystick::saveDeviceIdToSettings() +{ +#if LL_WINDOWS && !LL_MESA_HEADLESS + // can't save as binary directly, + // someone editing the xml will corrupt it + // so convert to string first + std::string device_string = getDeviceUUIDString(); + gSavedSettings.setLLSD("JoystickDeviceUUID", LLSD(device_string)); +#else + LLSD device_id = getDeviceUUID(); + gSavedSettings.setLLSD("JoystickDeviceUUID", device_id); #endif } void LLViewerJoystick::loadDeviceIdFromSettings() { + LLSD dev_id = gSavedSettings.getLLSD("JoystickDeviceUUID"); #if LL_WINDOWS && !LL_MESA_HEADLESS // We can't save binary data to gSavedSettings, somebody editing the file will corrupt it, // so _GUID data gets converted to string (we probably can convert it to LLUUID with memcpy) // and here we need to convert it back to binary from string - std::string device_string = gSavedSettings.getString("JoystickDeviceUUID"); + std::string device_string; + if (dev_id.isString()) + { + device_string = dev_id.asString(); + } if (device_string.empty()) { mLastDeviceUUID = LLSD(); @@ -1430,10 +1536,22 @@ void LLViewerJoystick::loadDeviceIdFromSettings() LLSD::Binary data; //just an std::vector data.resize(size); memcpy(&data[0], &guid /*POD _GUID*/, size); - // We store this data in LLSD since LLSD is versatile and will be able to handle both GUID2 - // and any data MAC will need for device selection + // We store this data in LLSD since it can handle both GUID2 and long mLastDeviceUUID = LLSD(data); } +#elif LL_DARWIN + if (!dev_id.isMap()) + { + mLastDeviceUUID = LLSD(); + } + else + { + std::string manufacturer = mLastDeviceUUID["manufacturer"].asString(); + std::string product = mLastDeviceUUID["product"].asString(); + LL_DEBUGS("Joystick") << "Looking for device by manufacturer: " << manufacturer << " and product: " << product << LL_ENDL; + // We store this data in LLSD since it can handle both GUID2 and long + mLastDeviceUUID = dev_id; + } #else mLastDeviceUUID = LLSD(); //mLastDeviceUUID = gSavedSettings.getLLSD("JoystickDeviceUUID"); diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index f3129412c7..1e68b9ccfe 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -30,6 +30,9 @@ #include "stdtypes.h" #if LIB_NDOF +#if LL_DARWIN +#define TARGET_OS_MAC 1 +#endif #include "ndofdev_external.h" #else #define NDOF_Device void @@ -60,8 +63,8 @@ class LLViewerJoystick : public LLSingleton public: void init(bool autoenable); void initDevice(LLSD &guid); - void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); - void initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); + bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); + bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/, std::string &name, LLSD &guid); void terminate(); void updateStatus(); @@ -84,6 +87,7 @@ public: LLSD getDeviceUUID(); //unconverted, OS dependent value wrapped into LLSD, for comparison/search std::string getDeviceUUIDString(); // converted readable value for settings std::string getDescription(); + void saveDeviceIdToSettings(); protected: void updateEnabled(bool autoenable); @@ -115,7 +119,11 @@ private: bool mCameraUpdated; bool mOverrideCamera; U32 mJoystickRun; - LLSD mLastDeviceUUID; // _GUID as U8 binary map, integer 1 for no device/ndof's device + + // Windows: _GUID as U8 binary map + // MacOS: long as an U8 binary map + // Else: integer 1 for no device/ndof's default device + LLSD mLastDeviceUUID; static F32 sLastDelta[7]; static F32 sDelta[7];