Merge branch 'DRTVWR-591-maint-X' of https://github.com/secondlife/viewer
# Conflicts: # indra/llui/lltransutil.cpp # indra/llwindow/llwindowmacosx.cpp # indra/llwindow/llwindowmacosx.h # indra/newview/app_settings/settings.xml # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llinspectavatar.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llviewerjoystick.cppmaster
commit
63f30264ff
|
|
@ -241,6 +241,7 @@ Ansariel Hiller
|
|||
SL-18432
|
||||
SL-19140
|
||||
SL-4126
|
||||
SL-20524
|
||||
Aralara Rajal
|
||||
Arare Chantilly
|
||||
CHUIBUG-191
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<s
|
|||
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS);
|
||||
if (!success)
|
||||
{
|
||||
gDirUtilp->dumpCurrentDirectories(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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
|
||||
void* win_callback,
|
||||
void* userdata)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual S32 getRefreshRate() { return mRefreshRate; }
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <errno.h>
|
||||
#include "llopenglview-objc.h"
|
||||
#include "llwindowmacosx-objc.h"
|
||||
#include "llappdelegate-objc.h"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,13 @@
|
|||
#include <CoreServices/CoreServices.h>
|
||||
#include <CoreGraphics/CGDisplayConfiguration.h>
|
||||
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/IOMessage.h>
|
||||
#include <IOKit/hid/IOHIDUsageTables.h>
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <IOKit/usb/IOUSBLib.h>
|
||||
|
||||
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<HidDevice> &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<bool(std::string&, LLSD&, void*)> 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<HidDevice> device_list;
|
||||
|
||||
get_devices(device_list, io_iter);
|
||||
|
||||
std::list<HidDevice>::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;
|
||||
|
|
|
|||
|
|
@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
|
||||
void* win_callback,
|
||||
void* userdata) override;
|
||||
|
||||
static std::vector<std::string> getDisplaysResolutionList();
|
||||
|
||||
|
|
|
|||
|
|
@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
|
||||
void * di8_devices_callback,
|
||||
void* userdata)
|
||||
{
|
||||
if (gDirectInput8 != NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<bool(std::string&, LLSD&, void*)> osx_callback,
|
||||
void* win_callback,
|
||||
void* userdata);
|
||||
|
||||
U32 getRawWParam() { return mRawWParam; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6517,7 +6517,7 @@
|
|||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<string>LLSD</string>
|
||||
<key>Value</key>
|
||||
<string />
|
||||
</map>
|
||||
|
|
|
|||
|
|
@ -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<LLAvatarData*>(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<LLAvatarData*>(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)
|
||||
|
|
|
|||
|
|
@ -50,10 +50,16 @@ public:
|
|||
|
||||
void sendAgentPicksRequest()
|
||||
{
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID());
|
||||
// <FS> OpenSim
|
||||
//LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID());
|
||||
if (!gAgent.getRegionCapability("AgentProfile").empty())
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID());
|
||||
else
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID());
|
||||
// </FS>
|
||||
}
|
||||
|
||||
typedef boost::function<void(LLAvatarPicks*)> server_respond_callback_t;
|
||||
typedef boost::function<void(LLAvatarData*)> 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<LLAvatarPicks*>(data);
|
||||
if(picks && gAgent.getID() == picks->target_id)
|
||||
LLAvatarData* picks = static_cast<LLAvatarData*>(data);
|
||||
if(picks && gAgent.getID() == picks->avatar_id)
|
||||
{
|
||||
if(mServerRespondCallback)
|
||||
{
|
||||
|
|
@ -73,6 +79,21 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
// <FS> OpenSim
|
||||
else if (APT_PICKS == type)
|
||||
{
|
||||
LLAvatarPicks* picks = static_cast<LLAvatarPicks*>(data);
|
||||
if (picks && gAgent.getID() == picks->target_id)
|
||||
{
|
||||
if (mServerRespondCallback)
|
||||
{
|
||||
LLAvatarData avatardata;
|
||||
avatardata.picks_list = picks->picks_list;
|
||||
mServerRespondCallback(&avatardata);
|
||||
}
|
||||
}
|
||||
}
|
||||
// </FS>
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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<LLAvatarData*>(data);
|
||||
LLAvatarLegacyData* avatar_data = static_cast<LLAvatarLegacyData*>(data);
|
||||
if (avatar_data)
|
||||
{
|
||||
if (avatar_data->avatar_id != mAvatarId)
|
||||
|
|
|
|||
|
|
@ -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<std::string> strings;
|
||||
strings.push_back(avatar_id.asString());
|
||||
std::vector<std::string> 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;
|
||||
// <FS:Zi> 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;
|
||||
|
||||
// <FS:Ansariel> Fix protocol bug
|
||||
//avatar_data.agent_id = agent_id;
|
||||
avatar_data.agent_id = gAgentID;
|
||||
// </FS:Ansariel>
|
||||
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())
|
||||
// </FS:Zi>
|
||||
{
|
||||
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
|
||||
// <FS:Ansariel> OpenSim
|
||||
//avatar_data.hide_age = TRUE;
|
||||
//avatar_data.hide_age = true;
|
||||
avatar_data.hide_age = LLGridManager::instance().isInSecondLife();
|
||||
// </FS:Ansariel>
|
||||
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
|
|||
// </FS:CR>
|
||||
}
|
||||
|
||||
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<std::string> 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);
|
||||
}
|
||||
|
||||
// <FS> 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<std::string> 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);
|
||||
}
|
||||
// </FS>
|
||||
|
|
@ -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; // <FS:Zi> 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
|
||||
// <FS> OpenSim
|
||||
APT_NOTES,
|
||||
APT_GROUPS,
|
||||
APT_PICKS,
|
||||
// </FS>
|
||||
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<LLGroupData> group_list_t;
|
||||
group_list_t group_list;
|
||||
|
||||
typedef std::pair<LLUUID, std::string> pick_data_t;
|
||||
typedef std::list< pick_data_t> picks_list_t;
|
||||
picks_list_t picks_list;
|
||||
BOOL allow_publish; // <FS:Ansariel> UDP profiles
|
||||
};
|
||||
|
||||
struct LLAvatarPicks
|
||||
struct LLAvatarData::LLGroupData
|
||||
{
|
||||
LLUUID agent_id;
|
||||
LLUUID target_id; //target id
|
||||
|
||||
typedef std::pair<LLUUID,std::string> 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;
|
||||
};
|
||||
|
||||
// <FS> OpenSim
|
||||
struct LLAvatarPicks
|
||||
{
|
||||
LLUUID agent_id;
|
||||
LLUUID target_id; //target id
|
||||
|
||||
typedef std::pair<LLUUID,std::string> 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;
|
||||
};
|
||||
};
|
||||
// </FS>
|
||||
|
||||
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);
|
||||
|
||||
// <FS> 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);
|
||||
// </FS>
|
||||
|
||||
// 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);
|
||||
|
||||
// <FS> 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**);
|
||||
|
||||
// <FS> OpenSim
|
||||
static void processAvatarGroupsReply(LLMessageSystem* msg, void**);
|
||||
|
||||
static void processAvatarNotesReply(LLMessageSystem* msg, void**);
|
||||
|
||||
static void processAvatarPicksReply(LLMessageSystem* msg, void**);
|
||||
|
||||
// </FS>
|
||||
static void processPickInfoReply(LLMessageSystem* msg, void**);
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -656,6 +656,9 @@ std::unique_ptr<std::vector<std::string>> 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<std::vector<std::string>> 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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
// <FS> OpenSim
|
||||
//processor->sendAvatarPropertiesRequest(mAvatarID);
|
||||
if (!gAgent.getRegionCapability("AgentProfile").empty())
|
||||
processor->sendAvatarPropertiesRequest(mAvatarID);
|
||||
else
|
||||
processor->sendAvatarLegacyPropertiesRequest(mAvatarID);
|
||||
// </FS>
|
||||
}
|
||||
|
||||
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<LLAvatarData*>(data);
|
||||
LLFloaterBuyCurrency::handleBuyCurrency(LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(avatar_data), mHasTarget, mName, mPrice);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType t
|
|||
{
|
||||
if ( APT_PROPERTIES_LEGACY == type )
|
||||
{
|
||||
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData );
|
||||
const LLAvatarLegacyData* pAvatarData = static_cast<const LLAvatarLegacyData*>( 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<LLComboBox>("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
|
||||
|
|
|
|||
|
|
@ -196,9 +196,11 @@ public:
|
|||
// send a request (duplicates will be suppressed inside the avatar
|
||||
// properties processor)
|
||||
// <FS:Ansariel> 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);
|
||||
// </FS:Ansariel>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -210,3 +210,16 @@ void LLPanelProfilePropertiesProcessorTab::setAvatarId(const LLUUID & avatar_id)
|
|||
LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelProfilePropertiesProcessorTab::updateData()
|
||||
{
|
||||
LLUUID avatar_id = getAvatarId();
|
||||
// <FS> OpenSim
|
||||
//if (!getStarted() && avatar_id.notNull())
|
||||
if (!getStarted() && avatar_id.notNull() && !gAgent.getRegionCapability("AgentProfile").empty())
|
||||
// </FS>
|
||||
{
|
||||
setIsLoading();
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(getAvatarId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@ LLPanelClassifiedInfo::LLPanelClassifiedInfo()
|
|||
LLPanelClassifiedInfo::~LLPanelClassifiedInfo()
|
||||
{
|
||||
sAllPanels.remove(this);
|
||||
|
||||
if (getAvatarId().notNull())
|
||||
{
|
||||
LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLPanelClassifiedInfo::postBuild()
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
// <FS:Zi> 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<LLPanel>(PANEL_PROFILE_VIEW, TRUE);
|
||||
LLPanelProfile *panel_profile = dynamic_cast<LLPanelProfile*>(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;
|
||||
|
||||
// <FS:Zi> 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())
|
||||
// </FS:Zi>
|
||||
{
|
||||
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<LLPanel>(PANEL_SECONDLIFE, TRUE);
|
||||
LLPanelProfileSecondLife *panel_sl = dynamic_cast<LLPanelProfileSecondLife*>(panel);
|
||||
if (panel_sl)
|
||||
{
|
||||
panel_sl->processProfileProperties(avatar_data);
|
||||
}
|
||||
|
||||
panel = floater_profile->findChild<LLPanel>(PANEL_WEB, TRUE);
|
||||
LLPanelProfileWeb *panel_web = dynamic_cast<LLPanelProfileWeb*>(panel);
|
||||
if (panel_web)
|
||||
{
|
||||
panel_web->setLoaded();
|
||||
}
|
||||
|
||||
panel = floater_profile->findChild<LLPanel>(PANEL_FIRSTLIFE, TRUE);
|
||||
LLPanelProfileFirstLife *panel_first = dynamic_cast<LLPanelProfileFirstLife*>(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<LLPanel>(PANEL_PICKS, TRUE);
|
||||
LLPanelProfilePicks *panel_picks = dynamic_cast<LLPanelProfilePicks*>(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<LLPanel>(PANEL_NOTES, TRUE);
|
||||
LLPanelProfileNotes *panel_notes = dynamic_cast<LLPanelProfileNotes*>(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<LLPanel> *handle)
|
||||
{
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
|
|
@ -885,7 +701,7 @@ void LLFloaterProfilePermissions::onCancel()
|
|||
// LLPanelProfileSecondLife
|
||||
|
||||
LLPanelProfileSecondLife::LLPanelProfileSecondLife()
|
||||
: LLPanelProfilePropertiesProcessorTab() // <FS:Beq/> alter ancestry to re-enable UDP
|
||||
: LLPanelProfilePropertiesProcessorTab()
|
||||
, mAvatarNameCacheConnection()
|
||||
, mHasUnsavedDescriptionChanges(false)
|
||||
, mWaitingForImageUpload(false)
|
||||
|
|
@ -1004,11 +820,11 @@ BOOL LLPanelProfileSecondLife::postBuild()
|
|||
}
|
||||
|
||||
// <FS:Zi> 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));
|
||||
}
|
||||
|
||||
// <FS:Beq> 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
|
||||
{
|
||||
// <FS:Beq> 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
|
||||
// </FS:Beq>
|
||||
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();
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
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<const LLAvatarData*>(data);
|
||||
if(avatar_data && getAvatarId() == avatar_data->avatar_id)
|
||||
{
|
||||
processProfileProperties(avatar_data);
|
||||
setLoaded();
|
||||
}
|
||||
}
|
||||
else if (APT_GROUPS == type)
|
||||
{
|
||||
LLAvatarGroups* avatar_groups = static_cast<LLAvatarGroups*>(data);
|
||||
if(avatar_groups && getAvatarId() == avatar_groups->avatar_id)
|
||||
{
|
||||
processGroupProperties(avatar_groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
void LLPanelProfileSecondLife::resetData()
|
||||
|
|
@ -1251,6 +1031,44 @@ void LLPanelProfileSecondLife::resetData()
|
|||
// </FS:Ansariel>
|
||||
}
|
||||
|
||||
void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type)
|
||||
{
|
||||
if (APT_PROPERTIES == type)
|
||||
{
|
||||
LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data);
|
||||
if (avatar_data && getAvatarId() == avatar_data->avatar_id)
|
||||
{
|
||||
processProfileProperties(avatar_data);
|
||||
}
|
||||
}
|
||||
|
||||
// <FS:Beq> 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<const LLAvatarData*>(data);
|
||||
if(avatar_data && getAvatarId() == avatar_data->avatar_id)
|
||||
{
|
||||
processProfileProperties(avatar_data);
|
||||
}
|
||||
}
|
||||
else if (APT_GROUPS == type)
|
||||
{
|
||||
LLAvatarGroups* avatar_groups = static_cast<LLAvatarGroups*>(data);
|
||||
if(avatar_groups && getAvatarId() == avatar_groups->avatar_id)
|
||||
{
|
||||
processGroupProperties(avatar_groups);
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
}
|
||||
|
||||
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()) { // <FS>
|
||||
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);
|
||||
} // </FS>
|
||||
|
||||
// <FS:Beq> Restore UDP profiles
|
||||
#ifdef OPENSIM
|
||||
if (LLGridManager::instance().isInOpenSim())
|
||||
|
|
@ -1307,6 +1138,7 @@ void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avat
|
|||
updateButtons();
|
||||
}
|
||||
|
||||
// <FS> 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);
|
||||
}
|
||||
// </FS>
|
||||
|
||||
void LLPanelProfileSecondLife::openGroupProfile()
|
||||
{
|
||||
|
|
@ -1690,14 +1523,15 @@ void LLPanelProfileSecondLife::fillAgeData(const LLAvatarData* avatar_data)
|
|||
// <FS:Ansariel> 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<LLUICtrl>("sl_birth_date")->setValue(name_and_date);
|
||||
|
||||
//LLUICtrl* userAgeCtrl = getChild<LLUICtrl>("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); // <FS:Beq/> 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() // <FS:Beq/> alter ancestry to re-enable UDP
|
||||
: LLPanelProfilePropertiesProcessorTab()
|
||||
, mHasUnsavedChanges(false)
|
||||
{
|
||||
}
|
||||
|
|
@ -3058,16 +2894,8 @@ void LLPanelProfileFirstLife::onDiscardDescriptionChanges()
|
|||
setDescriptionText(mCurrentDescription);
|
||||
}
|
||||
|
||||
// <FS:Beq> 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<const LLAvatarData*>(data);
|
||||
|
|
@ -3076,8 +2904,17 @@ void LLPanelProfileFirstLife::processProperties(void * data, EAvatarProcessorTyp
|
|||
processProperties(avatar_data);
|
||||
}
|
||||
}
|
||||
// <FS:Beq> Restore UDP profiles
|
||||
else if (gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty() && APT_PROPERTIES_LEGACY == type)
|
||||
{
|
||||
const LLAvatarData* avatar_data = static_cast<const LLAvatarData*>(data);
|
||||
if (avatar_data && getAvatarId() == avatar_data->avatar_id)
|
||||
{
|
||||
processProperties(avatar_data);
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data)
|
||||
{
|
||||
|
|
@ -3152,7 +2989,7 @@ void LLPanelProfileFirstLife::setLoaded()
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLPanelProfileNotes::LLPanelProfileNotes()
|
||||
: LLPanelProfilePropertiesProcessorTab() // <FS:Beq/> alter ancestry to re-enable UDP
|
||||
: LLPanelProfilePropertiesProcessorTab()
|
||||
, mHasUnsavedChanges(false)
|
||||
{
|
||||
|
||||
|
|
@ -3162,29 +2999,26 @@ LLPanelProfileNotes::~LLPanelProfileNotes()
|
|||
{
|
||||
}
|
||||
|
||||
// <FS:Beq> 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); });
|
||||
}
|
||||
// <FS:Beq> 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
|
||||
// </FS:Beq>
|
||||
{
|
||||
LLPanelProfilePropertiesProcessorTab::updateData();
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
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<LLAvatarData*>(data);
|
||||
if (avatar_data && getAvatarId() == avatar_data->avatar_id)
|
||||
{
|
||||
processProperties(avatar_data);
|
||||
}
|
||||
}
|
||||
|
||||
// <FS:Beq> Restore UDP profiles
|
||||
else if (gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP).empty() && APT_NOTES == type)
|
||||
{
|
||||
LLAvatarNotes* avatar_notes = static_cast<LLAvatarNotes*>(data);
|
||||
if (avatar_notes && getAvatarId() == avatar_notes->target_id)
|
||||
{
|
||||
LLAvatarData avatardata;
|
||||
avatardata.notes = avatar_notes->notes;
|
||||
processProperties(&avatardata);
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
}
|
||||
|
||||
void LLPanelProfileNotes::processProperties(const LLAvatarData* avatar_data)
|
||||
{
|
||||
setNotesText(avatar_data->notes);
|
||||
mNotesEditor->setEnabled(TRUE);
|
||||
setLoaded();
|
||||
}
|
||||
// <FS:Beq> 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<LLAvatarNotes*>(data);
|
||||
if (avatar_notes && getAvatarId() == avatar_notes->target_id)
|
||||
{
|
||||
processProperties(avatar_notes);
|
||||
}
|
||||
}
|
||||
}
|
||||
// </FS:Beq>
|
||||
|
||||
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); // <FS:Beq/> alter ancestry to re-enable UDP
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// LLPanelProfile
|
||||
|
|
@ -3396,17 +3227,17 @@ void LLPanelProfile::updateData()
|
|||
mPanelFirstlife->setIsLoading();
|
||||
mPanelNotes->setIsLoading();
|
||||
} // <FS:Beq/> 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); });
|
||||
}
|
||||
|
||||
// <FS:Beq> 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
|
||||
// </FS:Beq>
|
||||
|
|
|
|||
|
|
@ -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; // <FS> 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;
|
||||
|
||||
// <FS:Zi> 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.
|
||||
*/
|
||||
// <FS> 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;
|
||||
|
||||
// <FS> 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;
|
||||
|
||||
// <FS> 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
|
||||
|
|
|
|||
|
|
@ -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<LLAvatarData*>(data);
|
||||
if (avatar_picks && getAvatarId() == avatar_picks->avatar_id)
|
||||
{
|
||||
if (getSelfProfile())
|
||||
{
|
||||
LLAgentPicksInfo::getInstance()->onServerRespond(avatar_picks);
|
||||
}
|
||||
processProperties(avatar_picks);
|
||||
}
|
||||
}
|
||||
// <FS> OpenSim
|
||||
else if (APT_PICKS == type)
|
||||
{
|
||||
LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data);
|
||||
if (avatar_picks && getAvatarId() == avatar_picks->target_id)
|
||||
{
|
||||
processProperties(avatar_picks);
|
||||
LLAvatarData avatardata;
|
||||
avatardata.picks_list = avatar_picks->picks_list;
|
||||
processProperties(&avatardata);
|
||||
}
|
||||
}
|
||||
// </FS>
|
||||
}
|
||||
|
||||
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);
|
||||
// <FS> OpenSim
|
||||
//LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id);
|
||||
if (!gAgent.getRegionCapability("AgentProfile").empty())
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id);
|
||||
else
|
||||
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id);
|
||||
// </FS>
|
||||
}
|
||||
if (!getIsLoaded())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<bool(std::string&, LLSD&, void*)> 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<bool(std::string&, LLSD&, void*)> 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");
|
||||
|
|
|
|||
|
|
@ -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<LLViewerJoystick>
|
|||
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];
|
||||
|
|
|
|||
Loading…
Reference in New Issue