Display names from Phoenix. Thanks Wolfspirit!
That's quite a piece of work. I have NO idea how Jess can downplay the effort that went into this. And it's still not complete, local chat is not affected, perhaps group chat too.
This commit is contained in:
@@ -572,6 +572,22 @@
|
||||
<boolean>false</boolean>
|
||||
</map>
|
||||
|
||||
<!-- Server to client -->
|
||||
<key>DisplayNameUpdate</key>
|
||||
<map>
|
||||
<key>flavor</key>
|
||||
<string>llsd</string>
|
||||
<key>trusted-sender</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
<key>SetDisplayNameReply</key>
|
||||
<map>
|
||||
<key>flavor</key>
|
||||
<string>llsd</string>
|
||||
<key>trusted-sender</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
|
||||
</map>
|
||||
<key>capBans</key>
|
||||
|
||||
@@ -15,6 +15,7 @@ set(llcommon_SOURCE_FILES
|
||||
llapp.cpp
|
||||
llapr.cpp
|
||||
llassettype.cpp
|
||||
llavatarname.cpp
|
||||
llbase32.cpp
|
||||
llbase64.cpp
|
||||
llcommon.cpp
|
||||
@@ -85,6 +86,7 @@ set(llcommon_HEADER_FILES
|
||||
llassettype.h
|
||||
llassoclist.h
|
||||
llavatarconstants.h
|
||||
llavatarname.h
|
||||
llbase32.h
|
||||
llbase64.h
|
||||
llboost.h
|
||||
|
||||
117
indra/llcommon/llavatarname.cpp
Normal file
117
indra/llcommon/llavatarname.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file llavatarname.cpp
|
||||
* @brief Represents name-related data for an avatar, such as the
|
||||
* username/SLID ("bobsmith123" or "james.linden") and the display
|
||||
* name ("James Cook")
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
/*
|
||||
Ported to Phoenix by Wolfspirit Magic.
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llavatarname.h"
|
||||
|
||||
#include "lldate.h"
|
||||
#include "llsd.h"
|
||||
|
||||
// Store these in pre-built std::strings to avoid memory allocations in
|
||||
// LLSD map lookups
|
||||
static const std::string USERNAME("username");
|
||||
static const std::string DISPLAY_NAME("display_name");
|
||||
static const std::string LEGACY_FIRST_NAME("legacy_first_name");
|
||||
static const std::string LEGACY_LAST_NAME("legacy_last_name");
|
||||
static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
|
||||
static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
|
||||
static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
|
||||
|
||||
LLAvatarName::LLAvatarName()
|
||||
: mUsername(),
|
||||
mDisplayName(),
|
||||
mLegacyFirstName(),
|
||||
mLegacyLastName(),
|
||||
mIsDisplayNameDefault(false),
|
||||
mIsDummy(false),
|
||||
mExpires(F64_MAX),
|
||||
mNextUpdate(0.0)
|
||||
{ }
|
||||
|
||||
bool LLAvatarName::operator<(const LLAvatarName& rhs) const
|
||||
{
|
||||
if (mUsername == rhs.mUsername)
|
||||
return mDisplayName < rhs.mDisplayName;
|
||||
else
|
||||
return mUsername < rhs.mUsername;
|
||||
}
|
||||
|
||||
LLSD LLAvatarName::asLLSD() const
|
||||
{
|
||||
LLSD sd;
|
||||
sd[USERNAME] = mUsername;
|
||||
sd[DISPLAY_NAME] = mDisplayName;
|
||||
sd[LEGACY_FIRST_NAME] = mLegacyFirstName;
|
||||
sd[LEGACY_LAST_NAME] = mLegacyLastName;
|
||||
sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault;
|
||||
sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires);
|
||||
sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate);
|
||||
return sd;
|
||||
}
|
||||
|
||||
void LLAvatarName::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
mUsername = sd[USERNAME].asString();
|
||||
mDisplayName = sd[DISPLAY_NAME].asString();
|
||||
mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString();
|
||||
mLegacyLastName = sd[LEGACY_LAST_NAME].asString();
|
||||
mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean();
|
||||
LLDate expires = sd[DISPLAY_NAME_EXPIRES];
|
||||
mExpires = expires.secondsSinceEpoch();
|
||||
LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
|
||||
mNextUpdate = next_update.secondsSinceEpoch();
|
||||
}
|
||||
|
||||
std::string LLAvatarName::getCompleteName() const
|
||||
{
|
||||
std::string name;
|
||||
if (!mUsername.empty())
|
||||
{
|
||||
name = mDisplayName + " (" + mUsername + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...display names are off, legacy name is in mDisplayName
|
||||
name = mDisplayName;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string LLAvatarName::getLegacyName() const
|
||||
{
|
||||
std::string name;
|
||||
name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() );
|
||||
name = mLegacyFirstName;
|
||||
name += " ";
|
||||
name += mLegacyLastName;
|
||||
return name;
|
||||
}
|
||||
95
indra/llcommon/llavatarname.h
Normal file
95
indra/llcommon/llavatarname.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file llavatarname.h
|
||||
* @brief Represents name-related data for an avatar, such as the
|
||||
* username/SLID ("bobsmith123" or "james.linden") and the display
|
||||
* name ("James Cook")
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLAVATARNAME_H
|
||||
#define LLAVATARNAME_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class LLSD;
|
||||
|
||||
class LLAvatarName
|
||||
{
|
||||
public:
|
||||
LLAvatarName();
|
||||
|
||||
bool operator<(const LLAvatarName& rhs) const;
|
||||
|
||||
LLSD asLLSD() const;
|
||||
|
||||
void fromLLSD(const LLSD& sd);
|
||||
|
||||
// For normal names, returns "James Linden (james.linden)"
|
||||
// When display names are disabled returns just "James Linden"
|
||||
std::string getCompleteName() const;
|
||||
|
||||
// Returns "James Linden" or "bobsmith123 Resident" for backwards
|
||||
// compatibility with systems like voice and muting
|
||||
// *TODO: Eliminate this in favor of username only
|
||||
std::string getLegacyName() const;
|
||||
|
||||
// "bobsmith123" or "james.linden", US-ASCII only
|
||||
std::string mUsername;
|
||||
|
||||
// "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode
|
||||
// Contains data whether or not user has explicitly set
|
||||
// a display name; may duplicate their username.
|
||||
std::string mDisplayName;
|
||||
|
||||
// For "James Linden", "James"
|
||||
// For "bobsmith123", "bobsmith123"
|
||||
// Used to communicate with legacy systems like voice and muting which
|
||||
// rely on old-style names.
|
||||
// *TODO: Eliminate this in favor of username only
|
||||
std::string mLegacyFirstName;
|
||||
|
||||
// For "James Linden", "Linden"
|
||||
// For "bobsmith123", "Resident"
|
||||
// see above for rationale
|
||||
std::string mLegacyLastName;
|
||||
|
||||
// If true, both display name and SLID were generated from
|
||||
// a legacy first and last name, like "James Linden (james.linden)"
|
||||
bool mIsDisplayNameDefault;
|
||||
|
||||
// Under error conditions, we may insert "dummy" records with
|
||||
// names like "???" into caches as placeholders. These can be
|
||||
// shown in UI, but are not serialized.
|
||||
bool mIsDummy;
|
||||
|
||||
// Names can change, so need to keep track of when name was
|
||||
// last checked.
|
||||
// Unix time-from-epoch seconds for efficiency
|
||||
F64 mExpires;
|
||||
|
||||
// You can only change your name every N hours, so record
|
||||
// when the next update is allowed
|
||||
// Unix time-from-epoch seconds
|
||||
F64 mNextUpdate;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,7 @@ include_directories(
|
||||
set(llmessage_SOURCE_FILES
|
||||
llares.cpp
|
||||
llassetstorage.cpp
|
||||
llavatarnamecache.cpp
|
||||
llblowfishcipher.cpp
|
||||
llbuffer.cpp
|
||||
llbufferstream.cpp
|
||||
@@ -106,6 +107,7 @@ set(llmessage_HEADER_FILES
|
||||
|
||||
llares.h
|
||||
llassetstorage.h
|
||||
llavatarnamecache.h
|
||||
llblowfishcipher.h
|
||||
llbuffer.h
|
||||
llbufferstream.h
|
||||
|
||||
826
indra/llmessage/llavatarnamecache.cpp
Normal file
826
indra/llmessage/llavatarnamecache.cpp
Normal file
@@ -0,0 +1,826 @@
|
||||
/**
|
||||
* @file llavatarnamecache.cpp
|
||||
* @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
|
||||
* ("James Cook") from avatar UUIDs.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
/*
|
||||
Ported to Phoenix by Wolfspirit Magic.
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
|
||||
#include "llcachename.h" // we wrap this system
|
||||
#include "llframetimer.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace LLAvatarNameCache
|
||||
{
|
||||
use_display_name_signal_t mUseDisplayNamesSignal;
|
||||
|
||||
// Manual override for display names - can disable even if the region
|
||||
// supports it.
|
||||
bool sUseDisplayNames = true;
|
||||
|
||||
// Cache starts in a paused state until we can determine if the
|
||||
// current region supports display names.
|
||||
bool sRunning = false;
|
||||
|
||||
// Base lookup URL for name service.
|
||||
// On simulator, loaded from indra.xml
|
||||
// On viewer, usually a simulator capability (at People API team's request)
|
||||
// Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
|
||||
std::string sNameLookupURL;
|
||||
|
||||
// accumulated agent IDs for next query against service
|
||||
typedef std::set<LLUUID> ask_queue_t;
|
||||
ask_queue_t sAskQueue;
|
||||
|
||||
// agent IDs that have been requested, but with no reply
|
||||
// maps agent ID to frame time request was made
|
||||
typedef std::map<LLUUID, F64> pending_queue_t;
|
||||
pending_queue_t sPendingQueue;
|
||||
|
||||
// Callbacks to fire when we received a name.
|
||||
// May have multiple callbacks for a single ID, which are
|
||||
// represented as multiple slots bound to the signal.
|
||||
// Avoid copying signals via pointers.
|
||||
typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
|
||||
signal_map_t sSignalMap;
|
||||
|
||||
// names we know about
|
||||
typedef std::map<LLUUID, LLAvatarName> cache_t;
|
||||
cache_t sCache;
|
||||
|
||||
// Send bulk lookup requests a few times a second at most
|
||||
// only need per-frame timing resolution
|
||||
LLFrameTimer sRequestTimer;
|
||||
|
||||
// Periodically clean out expired entries from the cache
|
||||
//LLFrameTimer sEraseExpiredTimer;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Internal methods
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
// Handle name response off network.
|
||||
// Optionally skip adding to cache, used when this is a fallback to the
|
||||
// legacy name system.
|
||||
void processName(const LLUUID& agent_id,
|
||||
const LLAvatarName& av_name,
|
||||
bool add_to_cache);
|
||||
|
||||
void requestNamesViaCapability();
|
||||
|
||||
|
||||
// agent_id/group_id, first_name, last_name, is_group, user_data
|
||||
// Legacy name system callback
|
||||
void legacyNameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data);
|
||||
|
||||
void requestNamesViaLegacy();
|
||||
|
||||
// Fill in an LLAvatarName with the legacy name data
|
||||
void buildLegacyName(const std::string& full_name,
|
||||
LLAvatarName* av_name);
|
||||
|
||||
// Do a single callback to a given slot
|
||||
void fireSignal(const LLUUID& agent_id,
|
||||
const callback_slot_t& slot,
|
||||
const LLAvatarName& av_name);
|
||||
|
||||
// Is a request in-flight over the network?
|
||||
|
||||
// Erase expired names from cache
|
||||
void eraseExpired();
|
||||
|
||||
bool expirationFromCacheControl(LLSD headers, F64 *expires);
|
||||
}
|
||||
|
||||
/* Sample response:
|
||||
<?xml version="1.0"?>
|
||||
<llsd>
|
||||
<map>
|
||||
<key>agents</key>
|
||||
<array>
|
||||
<map>
|
||||
<key>display_name_next_update</key>
|
||||
<date>2010-04-16T21:34:02+00:00Z</date>
|
||||
<key>display_name_expires</key>
|
||||
<date>2010-04-16T21:32:26.142178+00:00Z</date>
|
||||
<key>display_name</key>
|
||||
<string>MickBot390 LLQABot</string>
|
||||
<key>sl_id</key>
|
||||
<string>mickbot390.llqabot</string>
|
||||
<key>id</key>
|
||||
<string>0012809d-7d2d-4c24-9609-af1230a37715</string>
|
||||
<key>is_display_name_default</key>
|
||||
<boolean>false</boolean>
|
||||
</map>
|
||||
<map>
|
||||
<key>display_name_next_update</key>
|
||||
<date>2010-04-16T21:34:02+00:00Z</date>
|
||||
<key>display_name_expires</key>
|
||||
<date>2010-04-16T21:32:26.142178+00:00Z</date>
|
||||
<key>display_name</key>
|
||||
<string>Bjork Gudmundsdottir</string>
|
||||
<key>sl_id</key>
|
||||
<string>sardonyx.linden</string>
|
||||
<key>id</key>
|
||||
<string>3941037e-78ab-45f0-b421-bd6e77c1804d</string>
|
||||
<key>is_display_name_default</key>
|
||||
<boolean>true</boolean>
|
||||
</map>
|
||||
</array>
|
||||
</map>
|
||||
</llsd>
|
||||
*/
|
||||
|
||||
class LLAvatarNameResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
private:
|
||||
// need to store agent ids that are part of this request in case of
|
||||
// an error, so we can flag them as unavailable
|
||||
std::vector<LLUUID> mAgentIDs;
|
||||
|
||||
// Need the headers to look up Expires: and Retry-After:
|
||||
LLSD mHeaders;
|
||||
|
||||
public:
|
||||
LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
|
||||
: mAgentIDs(agent_ids),
|
||||
mHeaders()
|
||||
{ }
|
||||
|
||||
/*virtual*/ void completedHeader(U32 status, const std::string& reason,
|
||||
const LLSD& headers)
|
||||
{
|
||||
mHeaders = headers;
|
||||
}
|
||||
|
||||
/*virtual*/ void result(const LLSD& content)
|
||||
{
|
||||
// Pull expiration out of headers if available
|
||||
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders);
|
||||
|
||||
LLSD agents = content["agents"];
|
||||
LLSD::array_const_iterator it = agents.beginArray();
|
||||
for ( ; it != agents.endArray(); ++it)
|
||||
{
|
||||
const LLSD& row = *it;
|
||||
LLUUID agent_id = row["id"].asUUID();
|
||||
|
||||
LLAvatarName av_name;
|
||||
av_name.fromLLSD(row);
|
||||
|
||||
// Use expiration time from header
|
||||
av_name.mExpires = expires;
|
||||
|
||||
// Some avatars don't have explicit display names set
|
||||
if (av_name.mDisplayName.empty())
|
||||
{
|
||||
av_name.mDisplayName = av_name.mUsername;
|
||||
}
|
||||
|
||||
// cache it and fire signals
|
||||
LLAvatarNameCache::processName(agent_id, av_name, true);
|
||||
}
|
||||
|
||||
// Same logic as error response case
|
||||
LLSD unresolved_agents = content["bad_ids"];
|
||||
if (unresolved_agents.size() > 0)
|
||||
{
|
||||
const std::string DUMMY_NAME("\?\?\?");
|
||||
LLAvatarName av_name;
|
||||
av_name.mUsername = DUMMY_NAME;
|
||||
av_name.mDisplayName = DUMMY_NAME;
|
||||
av_name.mIsDisplayNameDefault = false;
|
||||
av_name.mIsDummy = true;
|
||||
av_name.mExpires = expires;
|
||||
|
||||
it = unresolved_agents.beginArray();
|
||||
for ( ; it != unresolved_agents.endArray(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
// cache it and fire signals
|
||||
LLAvatarNameCache::processName(agent_id, av_name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
// We're going to construct a dummy record and cache it for a while,
|
||||
// either briefly for a 503 Service Unavailable, or longer for other
|
||||
// errors.
|
||||
F64 retry_timestamp = errorRetryTimestamp(status);
|
||||
|
||||
// *NOTE: "??" starts trigraphs in C/C++, escape the question marks.
|
||||
const std::string DUMMY_NAME("\?\?\?");
|
||||
LLAvatarName av_name;
|
||||
av_name.mUsername = DUMMY_NAME;
|
||||
av_name.mDisplayName = DUMMY_NAME;
|
||||
av_name.mIsDisplayNameDefault = false;
|
||||
av_name.mIsDummy = true;
|
||||
av_name.mExpires = retry_timestamp;
|
||||
|
||||
// Add dummy records for all agent IDs in this request
|
||||
std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
|
||||
for ( ; it != mAgentIDs.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
// cache it and fire signals
|
||||
LLAvatarNameCache::processName(agent_id, av_name, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Return time to retry a request that generated an error, based on
|
||||
// error type and headers. Return value is seconds-since-epoch.
|
||||
F64 errorRetryTimestamp(S32 status)
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
// Retry-After takes priority
|
||||
LLSD retry_after = mHeaders["retry-after"];
|
||||
if (retry_after.isDefined())
|
||||
{
|
||||
// We only support the delta-seconds type
|
||||
S32 delta_seconds = retry_after.asInteger();
|
||||
if (delta_seconds > 0)
|
||||
{
|
||||
// ...valid delta-seconds
|
||||
return now + F64(delta_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
// If no Retry-After, look for Cache-Control max-age
|
||||
F64 expires = 0.0;
|
||||
if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires))
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
|
||||
// No information in header, make a guess
|
||||
if (status == 503)
|
||||
{
|
||||
// ...service unavailable, retry soon
|
||||
const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
|
||||
return now + SERVICE_UNAVAILABLE_DELAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...other unexpected error
|
||||
const F64 DEFAULT_DELAY = 3600.0; // 1 hour
|
||||
return now + DEFAULT_DELAY;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void LLAvatarNameCache::processName(const LLUUID& agent_id,
|
||||
const LLAvatarName& av_name,
|
||||
bool add_to_cache)
|
||||
{
|
||||
if (add_to_cache)
|
||||
{
|
||||
sCache[agent_id] = av_name;
|
||||
}
|
||||
|
||||
sPendingQueue.erase(agent_id);
|
||||
|
||||
// signal everyone waiting on this name
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
|
||||
if (sig_it != sSignalMap.end())
|
||||
{
|
||||
callback_signal_t* signal = sig_it->second;
|
||||
(*signal)(agent_id, av_name);
|
||||
|
||||
sSignalMap.erase(agent_id);
|
||||
|
||||
delete signal;
|
||||
signal = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::requestNamesViaCapability()
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
|
||||
// URL format is like:
|
||||
// http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0
|
||||
//
|
||||
// Apache can handle URLs of 4096 chars, but let's be conservative
|
||||
const U32 NAME_URL_MAX = 4096;
|
||||
const U32 NAME_URL_SEND_THRESHOLD = 3000;
|
||||
std::string url;
|
||||
url.reserve(NAME_URL_MAX);
|
||||
|
||||
std::vector<LLUUID> agent_ids;
|
||||
agent_ids.reserve(128);
|
||||
|
||||
ask_queue_t::const_iterator it = sAskQueue.begin();
|
||||
for ( ; it != sAskQueue.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
|
||||
if (url.empty())
|
||||
{
|
||||
// ...starting new request
|
||||
url += sNameLookupURL;
|
||||
url += "?ids=";
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...continuing existing request
|
||||
url += "&ids=";
|
||||
}
|
||||
url += agent_id.asString();
|
||||
agent_ids.push_back(agent_id);
|
||||
|
||||
// mark request as pending
|
||||
sPendingQueue[agent_id] = now;
|
||||
|
||||
if (url.size() > NAME_URL_SEND_THRESHOLD)
|
||||
{
|
||||
//llinfos << "requestNames " << url << llendl;
|
||||
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
|
||||
url.clear();
|
||||
agent_ids.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
//llinfos << "requestNames " << url << llendl;
|
||||
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
|
||||
url.clear();
|
||||
agent_ids.clear();
|
||||
}
|
||||
|
||||
// We've moved all asks to the pending request queue
|
||||
sAskQueue.clear();
|
||||
}
|
||||
void LLAvatarNameCache::legacyNameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data)
|
||||
{
|
||||
std::string full_name = first + " " +last;
|
||||
// Construct a dummy record for this name. By convention, SLID is blank
|
||||
// Never expires, but not written to disk, so lasts until end of session.
|
||||
LLAvatarName av_name;
|
||||
buildLegacyName(full_name, &av_name);
|
||||
|
||||
// Don't add to cache, the data already exists in the legacy name system
|
||||
// cache and we don't want or need duplicate storage, because keeping the
|
||||
// two copies in sync is complex.
|
||||
processName(id, av_name, false);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::requestNamesViaLegacy()
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
std::string full_name;
|
||||
ask_queue_t::const_iterator it = sAskQueue.begin();
|
||||
for (; it != sAskQueue.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
|
||||
// Mark as pending first, just in case the callback is immediately
|
||||
// invoked below. This should never happen in practice.
|
||||
sPendingQueue[agent_id] = now;
|
||||
|
||||
gCacheName->get(agent_id, false, legacyNameCallback);
|
||||
}
|
||||
|
||||
// We've either answered immediately or moved all asks to the
|
||||
// pending queue
|
||||
sAskQueue.clear();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::initClass(bool running)
|
||||
{
|
||||
sRunning = running;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::cleanupClass()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::importFile(std::istream& istr)
|
||||
{
|
||||
LLSD data;
|
||||
S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
|
||||
if (parse_count < 1) return;
|
||||
|
||||
// by convention LLSD storage is a map
|
||||
// we only store one entry in the map
|
||||
LLSD agents = data["agents"];
|
||||
|
||||
LLUUID agent_id;
|
||||
LLAvatarName av_name;
|
||||
LLSD::map_const_iterator it = agents.beginMap();
|
||||
for ( ; it != agents.endMap(); ++it)
|
||||
{
|
||||
agent_id.set(it->first);
|
||||
av_name.fromLLSD( it->second );
|
||||
sCache[agent_id] = av_name;
|
||||
}
|
||||
// entries may have expired since we last ran the viewer, just
|
||||
// clean them out now
|
||||
eraseExpired();
|
||||
llinfos << "loaded " << sCache.size() << llendl;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::exportFile(std::ostream& ostr)
|
||||
{
|
||||
LLSD agents;
|
||||
cache_t::const_iterator it = sCache.begin();
|
||||
for ( ; it != sCache.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = it->first;
|
||||
const LLAvatarName& av_name = it->second;
|
||||
if (!av_name.mIsDummy)
|
||||
{
|
||||
// key must be a string
|
||||
agents[agent_id.asString()] = av_name.asLLSD();
|
||||
}
|
||||
}
|
||||
LLSD data;
|
||||
data["agents"] = agents;
|
||||
LLSDSerialize::toPrettyXML(data, ostr);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url)
|
||||
{
|
||||
sNameLookupURL = name_lookup_url;
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::hasNameLookupURL()
|
||||
{
|
||||
return !sNameLookupURL.empty();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::idle()
|
||||
{
|
||||
// By convention, start running at first idle() call
|
||||
sRunning = true;
|
||||
|
||||
// *TODO: Possibly re-enabled this based on People API load measurements
|
||||
// 100 ms is the threshold for "user speed" operations, so we can
|
||||
// stall for about that long to batch up requests.
|
||||
//const F32 SECS_BETWEEN_REQUESTS = 0.1f;
|
||||
//if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Must be large relative to above
|
||||
|
||||
// No longer deleting expired entries, just re-requesting in the get
|
||||
// this way first synchronous get call on an expired entry won't return
|
||||
// legacy name. LF
|
||||
|
||||
//const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
|
||||
//if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
|
||||
//{
|
||||
// eraseExpired();
|
||||
//}
|
||||
|
||||
if (sAskQueue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (useDisplayNames())
|
||||
{
|
||||
requestNamesViaCapability();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...fall back to legacy name cache system
|
||||
requestNamesViaLegacy();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id)
|
||||
{
|
||||
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
F64 expire_time = now - PENDING_TIMEOUT_SECS;
|
||||
|
||||
pending_queue_t::const_iterator it = sPendingQueue.find(agent_id);
|
||||
if (it != sPendingQueue.end())
|
||||
{
|
||||
bool request_expired = (it->second < expire_time);
|
||||
return !request_expired;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::eraseExpired()
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
cache_t::iterator it = sCache.begin();
|
||||
while (it != sCache.end())
|
||||
{
|
||||
cache_t::iterator cur = it;
|
||||
++it;
|
||||
const LLAvatarName& av_name = cur->second;
|
||||
if (av_name.mExpires < now)
|
||||
{
|
||||
sCache.erase(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
|
||||
LLAvatarName* av_name)
|
||||
{
|
||||
llassert(av_name);
|
||||
av_name->mUsername = "";
|
||||
av_name->mDisplayName = full_name;
|
||||
av_name->mIsDisplayNameDefault = true;
|
||||
av_name->mIsDummy = true;
|
||||
av_name->mExpires = F64_MAX;
|
||||
}
|
||||
|
||||
// fills in av_name if it has it in the cache, even if expired (can check expiry time)
|
||||
// returns bool specifying if av_name was filled, false otherwise
|
||||
bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
|
||||
{
|
||||
if (sRunning)
|
||||
{
|
||||
// ...only do immediate lookups when cache is running
|
||||
if (useDisplayNames())
|
||||
{
|
||||
|
||||
// ...use display names cache
|
||||
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
|
||||
if (it != sCache.end())
|
||||
{
|
||||
*av_name = it->second;
|
||||
|
||||
// re-request name if entry is expired
|
||||
if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
|
||||
{
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// ...use legacy names cache
|
||||
std::string full_name;
|
||||
if (gCacheName->getFullName(agent_id, full_name))
|
||||
{
|
||||
buildLegacyName(full_name, av_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
|
||||
const callback_slot_t& slot,
|
||||
const LLAvatarName& av_name)
|
||||
{
|
||||
callback_signal_t signal;
|
||||
signal.connect(slot);
|
||||
signal(agent_id, av_name);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
|
||||
{
|
||||
if (sRunning)
|
||||
{
|
||||
// ...only do immediate lookups when cache is running
|
||||
if (useDisplayNames())
|
||||
{
|
||||
// ...use new cache
|
||||
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
|
||||
if (it != sCache.end())
|
||||
{
|
||||
LLAvatarName& av_name = it->second;
|
||||
|
||||
if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
|
||||
{
|
||||
av_name.mDisplayName = av_name.mDisplayName;
|
||||
// ...name already exists in cache, fire callback now
|
||||
fireSignal(agent_id, slot, av_name);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...use old name system
|
||||
std::string full_name;
|
||||
if (gCacheName->getFullName(agent_id, full_name))
|
||||
{
|
||||
LLAvatarName av_name;
|
||||
av_name.mDisplayName = av_name.mDisplayName;
|
||||
buildLegacyName(full_name, &av_name);
|
||||
fireSignal(agent_id, slot, av_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// schedule a request
|
||||
if (!isRequestPending(agent_id))
|
||||
{
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
|
||||
// always store additional callback, even if request is pending
|
||||
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
|
||||
if (sig_it == sSignalMap.end())
|
||||
{
|
||||
// ...new callback for this id
|
||||
callback_signal_t* signal = new callback_signal_t();
|
||||
signal->connect(slot);
|
||||
sSignalMap[agent_id] = signal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...existing callback, bind additional slot
|
||||
callback_signal_t* signal = sig_it->second;
|
||||
signal->connect(slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAvatarNameCache::setUseDisplayNames(bool use)
|
||||
{
|
||||
if (use != sUseDisplayNames)
|
||||
{
|
||||
sUseDisplayNames = use;
|
||||
// flush our cache
|
||||
sCache.clear();
|
||||
|
||||
mUseDisplayNamesSignal();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::useDisplayNames()
|
||||
{
|
||||
// Must be both manually set on and able to look up names.
|
||||
return sUseDisplayNames && !sNameLookupURL.empty();
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::erase(const LLUUID& agent_id)
|
||||
{
|
||||
sCache.erase(agent_id);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::fetch(const LLUUID& agent_id)
|
||||
{
|
||||
// re-request, even if request is already pending
|
||||
sAskQueue.insert(agent_id);
|
||||
}
|
||||
|
||||
void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name)
|
||||
{
|
||||
// *TODO: update timestamp if zero?
|
||||
sCache[agent_id] = av_name;
|
||||
}
|
||||
|
||||
F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
|
||||
{
|
||||
F64 expires = 0.0;
|
||||
if (expirationFromCacheControl(headers, &expires))
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
else
|
||||
{
|
||||
// With no expiration info, default to an hour
|
||||
const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
return now + DEFAULT_EXPIRES;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
|
||||
{
|
||||
// Allow the header to override the default
|
||||
LLSD cache_control_header = headers["cache-control"];
|
||||
if (cache_control_header.isDefined())
|
||||
{
|
||||
S32 max_age = 0;
|
||||
std::string cache_control = cache_control_header.asString();
|
||||
if (max_age_from_cache_control(cache_control, &max_age))
|
||||
{
|
||||
F64 now = LLFrameTimer::getTotalSeconds();
|
||||
*expires = now + (F64)max_age;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)
|
||||
{
|
||||
mUseDisplayNamesSignal.connect(cb);
|
||||
}
|
||||
|
||||
|
||||
static const std::string MAX_AGE("max-age");
|
||||
static const boost::char_separator<char> EQUALS_SEPARATOR("=");
|
||||
static const boost::char_separator<char> COMMA_SEPARATOR(",");
|
||||
|
||||
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age)
|
||||
{
|
||||
// Split the string on "," to get a list of directives
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
||||
tokenizer directives(cache_control, COMMA_SEPARATOR);
|
||||
|
||||
tokenizer::iterator token_it = directives.begin();
|
||||
for ( ; token_it != directives.end(); ++token_it)
|
||||
{
|
||||
// Tokens may have leading or trailing whitespace
|
||||
std::string token = *token_it;
|
||||
LLStringUtil::trim(token);
|
||||
|
||||
if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0)
|
||||
{
|
||||
// ...this token starts with max-age, so let's chop it up by "="
|
||||
tokenizer subtokens(token, EQUALS_SEPARATOR);
|
||||
tokenizer::iterator subtoken_it = subtokens.begin();
|
||||
|
||||
// Must have a token
|
||||
if (subtoken_it == subtokens.end()) return false;
|
||||
std::string subtoken = *subtoken_it;
|
||||
|
||||
// Must exactly equal "max-age"
|
||||
LLStringUtil::trim(subtoken);
|
||||
if (subtoken != MAX_AGE) return false;
|
||||
|
||||
// Must have another token
|
||||
++subtoken_it;
|
||||
if (subtoken_it == subtokens.end()) return false;
|
||||
subtoken = *subtoken_it;
|
||||
|
||||
// Must be a valid integer
|
||||
// *NOTE: atoi() returns 0 for invalid values, so we have to
|
||||
// check the string first.
|
||||
// *TODO: Do servers ever send "0000" for zero? We don't handle it
|
||||
LLStringUtil::trim(subtoken);
|
||||
if (subtoken == "0")
|
||||
{
|
||||
*max_age = 0;
|
||||
return true;
|
||||
}
|
||||
S32 val = atoi( subtoken.c_str() );
|
||||
if (val > 0 && val < S32_MAX)
|
||||
{
|
||||
*max_age = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
104
indra/llmessage/llavatarnamecache.h
Normal file
104
indra/llmessage/llavatarnamecache.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file llavatarnamecache.h
|
||||
* @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names
|
||||
* ("James Cook") from avatar UUIDs.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLAVATARNAMECACHE_H
|
||||
#define LLAVATARNAMECACHE_H
|
||||
|
||||
#include "llavatarname.h" // for convenience
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLSD;
|
||||
class LLUUID;
|
||||
|
||||
namespace LLAvatarNameCache
|
||||
{
|
||||
|
||||
typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
|
||||
|
||||
// Until the cache is set running, immediate lookups will fail and
|
||||
// async lookups will be queued. This allows us to block requests
|
||||
// until we know if the first region supports display names.
|
||||
void initClass(bool running);
|
||||
void cleanupClass();
|
||||
|
||||
void importFile(std::istream& istr);
|
||||
void exportFile(std::ostream& ostr);
|
||||
|
||||
// On the viewer, usually a simulator capabilitity
|
||||
// If empty, name cache will fall back to using legacy name
|
||||
// lookup system
|
||||
void setNameLookupURL(const std::string& name_lookup_url);
|
||||
|
||||
// Do we have a valid lookup URL, hence are we trying to use the
|
||||
// new display name lookup system?
|
||||
bool hasNameLookupURL();
|
||||
|
||||
// Periodically makes a batch request for display names not already in
|
||||
// cache. Call once per frame.
|
||||
void idle();
|
||||
|
||||
// If name is in cache, returns true and fills in provided LLAvatarName
|
||||
// otherwise returns false
|
||||
bool get(const LLUUID& agent_id, LLAvatarName *av_name);
|
||||
|
||||
// Callback types for get() below
|
||||
typedef boost::signals2::signal<
|
||||
void (const LLUUID& agent_id, const LLAvatarName& av_name)>
|
||||
callback_signal_t;
|
||||
typedef callback_signal_t::slot_type callback_slot_t;
|
||||
|
||||
// Fetches name information and calls callback.
|
||||
// If name information is in cache, callback will be called immediately.
|
||||
void get(const LLUUID& agent_id, callback_slot_t slot);
|
||||
|
||||
// Allow display names to be explicitly disabled for testing.
|
||||
void setUseDisplayNames(bool use);
|
||||
bool useDisplayNames();
|
||||
bool isRequestPending(const LLUUID& agent_id);
|
||||
|
||||
void erase(const LLUUID& agent_id);
|
||||
|
||||
// Force a re-fetch of the most recent data, but keep the current
|
||||
// data in cache
|
||||
void fetch(const LLUUID& agent_id);
|
||||
|
||||
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
|
||||
|
||||
// Compute name expiration time from HTTP Cache-Control header,
|
||||
// or return default value, in seconds from epoch.
|
||||
F64 nameExpirationFromHeaders(LLSD headers);
|
||||
|
||||
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
|
||||
}
|
||||
|
||||
// Parse a cache-control header to get the max-age delta-seconds.
|
||||
// Returns true if header has max-age param and it parses correctly.
|
||||
// Exported here to ease unit testing.
|
||||
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
|
||||
|
||||
#endif
|
||||
@@ -154,6 +154,8 @@ set(viewer_SOURCE_FILES
|
||||
llfloateravatartextures.cpp
|
||||
llfloaterbeacons.cpp
|
||||
llfloaterblacklist.cpp
|
||||
llviewerdisplayname.cpp
|
||||
llfloaterdisplayname.cpp
|
||||
llfloaterbuildoptions.cpp
|
||||
llfloaterbulkpermission.cpp
|
||||
llfloaterbump.cpp
|
||||
@@ -612,7 +614,9 @@ set(viewer_HEADER_FILES
|
||||
llfloateravatarpicker.h
|
||||
llfloateravatartextures.h
|
||||
llfloaterbeacons.h
|
||||
llfloaterblacklist.h
|
||||
llfloaterblacklist.h
|
||||
llviewerdisplayname.h
|
||||
llfloaterdisplayname.h
|
||||
llfloaterbuildoptions.h
|
||||
llfloaterbulkpermission.h
|
||||
llfloaterbump.h
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
<!-- !!! settings_ascent.xml -->
|
||||
|
||||
|
||||
<key>PhoenixNameSystem</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use Display Names instead of Legacy Names. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<!-- Ascent-Specific Settings -->
|
||||
<key>AscentPowerfulWizard</key>
|
||||
<map>
|
||||
|
||||
@@ -171,10 +171,7 @@
|
||||
#include "llviewerthrottle.h"
|
||||
#include "llparcel.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llinventoryview.h"
|
||||
|
||||
#include "llcommandlineparser.h"
|
||||
@@ -1199,6 +1196,8 @@ bool LLAppViewer::cleanup()
|
||||
|
||||
LLPolyMesh::freeAllMeshes();
|
||||
|
||||
LLAvatarNameCache::cleanupClass();
|
||||
|
||||
delete gCacheName;
|
||||
gCacheName = NULL;
|
||||
|
||||
@@ -3201,6 +3200,15 @@ void LLAppViewer::saveFinalSnapshot()
|
||||
|
||||
void LLAppViewer::loadNameCache()
|
||||
{
|
||||
// Phoenix: Wolfspirit: Loads the Display Name Cache. And set if we are using Display Names.
|
||||
std::string filename =
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
|
||||
llifstream name_cache_stream(filename);
|
||||
if(name_cache_stream.is_open())
|
||||
{
|
||||
LLAvatarNameCache::importFile(name_cache_stream);
|
||||
}
|
||||
|
||||
if (!gCacheName) return;
|
||||
|
||||
std::string name_cache;
|
||||
@@ -3223,6 +3231,15 @@ void LLAppViewer::loadNameCache()
|
||||
|
||||
void LLAppViewer::saveNameCache()
|
||||
{
|
||||
// Phoenix: Wolfspirit: Saves the Display Name Cache.
|
||||
std::string filename =
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
|
||||
llofstream name_cache_stream(filename);
|
||||
if(name_cache_stream.is_open())
|
||||
{
|
||||
LLAvatarNameCache::exportFile(name_cache_stream);
|
||||
}
|
||||
|
||||
if (!gCacheName) return;
|
||||
|
||||
std::string name_cache;
|
||||
@@ -3406,6 +3423,9 @@ void LLAppViewer::idle()
|
||||
{
|
||||
LLFastTimer t(LLFastTimer::FTM_NETWORK);
|
||||
|
||||
// Phoenix: Wolfspirit: Prepare the namecache.
|
||||
idleNameCache();
|
||||
|
||||
////////////////////////////////////////////////
|
||||
//
|
||||
// Network processing
|
||||
@@ -3739,6 +3759,61 @@ public:
|
||||
|
||||
};
|
||||
|
||||
void LLAppViewer::idleNameCache()
|
||||
{
|
||||
// Neither old nor new name cache can function before agent has a region
|
||||
LLViewerRegion* region = gAgent.getRegion();
|
||||
if (!region) return;
|
||||
|
||||
// deal with any queued name requests and replies.
|
||||
gCacheName->processPending();
|
||||
|
||||
// Can't run the new cache until we have the list of capabilities
|
||||
// for the agent region, and can therefore decide whether to use
|
||||
// display names or fall back to the old name system.
|
||||
if (!region->capabilitiesReceived()) return;
|
||||
|
||||
// Agent may have moved to a different region, so need to update cap URL
|
||||
// for name lookups. Can't do this in the cap grant code, as caps are
|
||||
// granted to neighbor regions before the main agent gets there. Can't
|
||||
// do it in the move-into-region code because cap not guaranteed to be
|
||||
// granted yet, for example on teleport.
|
||||
bool had_capability = LLAvatarNameCache::hasNameLookupURL();
|
||||
std::string name_lookup_url;
|
||||
name_lookup_url.reserve(128); // avoid a memory allocation below
|
||||
name_lookup_url = region->getCapability("GetDisplayNames");
|
||||
bool have_capability = !name_lookup_url.empty();
|
||||
if (have_capability)
|
||||
{
|
||||
// we have support for display names, use it
|
||||
U32 url_size = name_lookup_url.size();
|
||||
// capabilities require URLs with slashes before query params:
|
||||
// https://<host>:<port>/cap/<uuid>/?ids=<blah>
|
||||
// but the caps are granted like:
|
||||
// https://<host>:<port>/cap/<uuid>
|
||||
if (url_size > 0 && name_lookup_url[url_size-1] != '/')
|
||||
{
|
||||
name_lookup_url += '/';
|
||||
}
|
||||
LLAvatarNameCache::setNameLookupURL(name_lookup_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display names not available on this region
|
||||
LLAvatarNameCache::setNameLookupURL( std::string() );
|
||||
}
|
||||
|
||||
// Error recovery - did we change state?
|
||||
if (had_capability != have_capability)
|
||||
{
|
||||
// name tags are persistant on screen, so make sure they refresh
|
||||
//LLVOAvatar::invalidateNameTags();
|
||||
}
|
||||
|
||||
|
||||
// Phoenix: Wolfspirit: Check if we are using Display Names and set it. Then idle the cache.
|
||||
LLAvatarNameCache::idle();
|
||||
}
|
||||
|
||||
void LLAppViewer::sendLogoutRequest()
|
||||
{
|
||||
|
||||
@@ -195,6 +195,7 @@ private:
|
||||
void idle();
|
||||
void idleShutdown();
|
||||
void idleNetwork();
|
||||
void idleNameCache();
|
||||
|
||||
void sendLogoutRequest();
|
||||
void disconnectViewer();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloateravatarinfo.h"
|
||||
#include "llavatarnamecache.h"
|
||||
|
||||
// viewer project includes
|
||||
#include "llagentdata.h"
|
||||
@@ -47,6 +48,7 @@
|
||||
#include "lluuid.h"
|
||||
#include "message.h"
|
||||
|
||||
|
||||
const char FLOATER_TITLE[] = "Profile";
|
||||
const LLRect FAI_RECT(0, 530, 420, 0);
|
||||
|
||||
@@ -122,7 +124,8 @@ LLFloaterAvatarInfo::LLFloaterAvatarInfo(const std::string& name, const LLRect &
|
||||
}
|
||||
|
||||
gAvatarInfoInstances.addData(avatar_id, this); // must be done before callback below is called.
|
||||
gCacheName->get(avatar_id, FALSE, callbackLoadAvatarName);
|
||||
//gCacheName->get(avatar_id, FALSE, callbackLoadAvatarName);
|
||||
LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterAvatarInfo::callbackLoadAvatarName, _1, _2));
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -242,10 +245,7 @@ void LLFloaterAvatarInfo::showProfileCallback(S32 option, void *userdata)
|
||||
|
||||
// static
|
||||
void LLFloaterAvatarInfo::callbackLoadAvatarName(const LLUUID& id,
|
||||
const std::string& first,
|
||||
const std::string& last,
|
||||
BOOL is_group,
|
||||
void* data)
|
||||
const LLAvatarName& av_name)
|
||||
{
|
||||
LLFloaterAvatarInfo *floater = gAvatarInfoInstances.getIfThere(id);
|
||||
|
||||
@@ -253,7 +253,8 @@ void LLFloaterAvatarInfo::callbackLoadAvatarName(const LLUUID& id,
|
||||
{
|
||||
// Build a new title including the avatar name.
|
||||
std::ostringstream title;
|
||||
title << first << " " << last << " - " << floater->getTitle();
|
||||
//title << first << " " << last << " - " << floater->getTitle();
|
||||
title << av_name.getCompleteName()<< " - " << floater->getTitle();
|
||||
floater->setTitle(title.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "lluuid.h"
|
||||
#include "llpanelavatar.h"
|
||||
|
||||
class LLAvatarName;
|
||||
class LLButton;
|
||||
class LLCheckBoxCtrl;
|
||||
class LLDropTarget;
|
||||
@@ -91,8 +92,7 @@ public:
|
||||
|
||||
static LLFloaterAvatarInfo* getInstance(const LLUUID &id);
|
||||
static void showProfileCallback(S32 option, void *userdata);
|
||||
static void callbackLoadAvatarName(const LLUUID& id,
|
||||
const std::string& first, const std::string& last, BOOL is_group, void* data);
|
||||
static void callbackLoadAvatarName(const LLUUID& agent_id, const LLAvatarName& av_name);
|
||||
void resetGroupList();
|
||||
|
||||
private:
|
||||
|
||||
232
indra/newview/llfloaterdisplayname.cpp
Normal file
232
indra/newview/llfloaterdisplayname.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* @file llfloaterdisplayname.cpp
|
||||
* @author Leyla Farazha
|
||||
* @brief Implementation of the LLFloaterDisplayName class.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llfloater.h"
|
||||
|
||||
#include "llnotifications.h"
|
||||
#include "llviewerdisplayname.h"
|
||||
|
||||
#include "llnotify.h"
|
||||
#include "llfloaterdisplayname.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
#include "llagent.h"
|
||||
|
||||
|
||||
LLFloaterDisplayName* LLFloaterDisplayName::sInstance = NULL;
|
||||
|
||||
LLFloaterDisplayName::LLFloaterDisplayName()
|
||||
: LLFloater(std::string("Display Names Floater"))
|
||||
{
|
||||
LLFloaterDisplayName::sInstance = this;
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLFloaterDisplayName::~LLFloaterDisplayName()
|
||||
{
|
||||
|
||||
LLFloaterDisplayName::sInstance = NULL;
|
||||
|
||||
}
|
||||
|
||||
BOOL LLFloaterDisplayName::postBuild()
|
||||
{
|
||||
childSetAction("reset_btn", onReset, this);
|
||||
childSetAction("cancel_btn", onCancel, this);
|
||||
childSetAction("save_btn", onSave, this);
|
||||
|
||||
center();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFloaterDisplayName::show()
|
||||
{
|
||||
if (LLFloaterDisplayName::sInstance)
|
||||
{
|
||||
LLFloaterDisplayName::sInstance->open(); /*Flawfinder: ignore*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LLFloaterDisplayName *self = new LLFloaterDisplayName();
|
||||
|
||||
// Builds and adds to gFloaterView
|
||||
LLUICtrlFactory::getInstance()->buildFloater(self, "floater_display_name.xml");
|
||||
|
||||
// Fix up rectangle
|
||||
|
||||
self->open(); /*Flawfinder: ignore*/
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterDisplayName::onOpen()
|
||||
{
|
||||
getChild<LLUICtrl>("display_name_editor")->clear();
|
||||
getChild<LLUICtrl>("display_name_confirm")->clear();
|
||||
|
||||
LLAvatarName av_name;
|
||||
LLAvatarNameCache::get(gAgent.getID(), &av_name);
|
||||
|
||||
F64 now_secs = LLDate::now().secondsSinceEpoch();
|
||||
|
||||
if (now_secs < av_name.mNextUpdate)
|
||||
{
|
||||
// ...can't update until some time in the future
|
||||
F64 next_update_local_secs =
|
||||
av_name.mNextUpdate ;
|
||||
LLDate next_update_local(next_update_local_secs);
|
||||
// display as "July 18 12:17 PM"
|
||||
// std::string next_update_string =
|
||||
// next_update_local.toHTTPDateString("%B %d %I:%M %p");
|
||||
std::string next_update_string = next_update_local.asString();
|
||||
getChild<LLUICtrl>("lockout_text")->setTextArg("[TIME]", next_update_string);
|
||||
getChild<LLUICtrl>("lockout_text")->setVisible(true);
|
||||
getChild<LLUICtrl>("save_btn")->setEnabled(false);
|
||||
getChild<LLUICtrl>("display_name_editor")->setEnabled(false);
|
||||
getChild<LLUICtrl>("display_name_confirm")->setEnabled(false);
|
||||
getChild<LLUICtrl>("cancel_btn")->setFocus(TRUE);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
getChild<LLUICtrl>("lockout_text")->setVisible(false);
|
||||
getChild<LLUICtrl>("save_btn")->setEnabled(true);
|
||||
getChild<LLUICtrl>("display_name_editor")->setEnabled(true);
|
||||
getChild<LLUICtrl>("display_name_confirm")->setEnabled(true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterDisplayName::onCacheSetName(bool success,
|
||||
const std::string& reason,
|
||||
const LLSD& content)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
// Inform the user that the change took place, but will take a while
|
||||
// to percolate.
|
||||
LLSD args;
|
||||
args["DISPLAY_NAME"] = content["display_name"];
|
||||
LLNotifications::instance().add("SetDisplayNameSuccess", args);
|
||||
|
||||
// Re-fetch my name, as it may have been sanitized by the service
|
||||
//LLAvatarNameCache::get(getAvatarId(),
|
||||
// boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2));
|
||||
return;
|
||||
}
|
||||
|
||||
// Request failed, notify the user
|
||||
std::string error_tag = content["error_tag"].asString();
|
||||
llinfos << "set name failure error_tag " << error_tag << llendl;
|
||||
|
||||
// We might have a localized string for this message
|
||||
// error_args will usually be empty from the server.
|
||||
if (!error_tag.empty()
|
||||
&& LLNotifications::getInstance()->templateExists(error_tag))
|
||||
{
|
||||
LLNotifications::instance().add(error_tag);
|
||||
return;
|
||||
}
|
||||
|
||||
// The server error might have a localized message for us
|
||||
std::string lang_code = LLUI::getLanguage();
|
||||
LLSD error_desc = content["error_description"];
|
||||
if (error_desc.has( lang_code ))
|
||||
{
|
||||
LLSD args;
|
||||
args["MESSAGE"] = error_desc[lang_code].asString();
|
||||
LLNotifications::instance().add("GenericAlert", args);
|
||||
return;
|
||||
}
|
||||
|
||||
// No specific error, throw a generic one
|
||||
LLNotifications::instance().add("SetDisplayNameFailedGeneric");
|
||||
}
|
||||
|
||||
void LLFloaterDisplayName::onCancel(void* data)
|
||||
{
|
||||
LLFloaterDisplayName* self = (LLFloaterDisplayName*)data;
|
||||
self->setVisible(false);
|
||||
}
|
||||
|
||||
void LLFloaterDisplayName::onReset(void* data)
|
||||
{
|
||||
LLFloaterDisplayName* self = (LLFloaterDisplayName*)data;
|
||||
if (LLAvatarNameCache::useDisplayNames())
|
||||
{
|
||||
LLViewerDisplayName::set("",
|
||||
boost::bind(&LLFloaterDisplayName::onCacheSetName, self, _1, _2, _3));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotifications::instance().add("SetDisplayNameFailedGeneric");
|
||||
}
|
||||
|
||||
self->setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterDisplayName::onSave(void* data)
|
||||
{
|
||||
LLFloaterDisplayName* self = (LLFloaterDisplayName*)data;
|
||||
std::string display_name_utf8 = self->getChild<LLUICtrl>("display_name_editor")->getValue().asString();
|
||||
std::string display_name_confirm = self->getChild<LLUICtrl>("display_name_confirm")->getValue().asString();
|
||||
|
||||
if (display_name_utf8.compare(display_name_confirm))
|
||||
{
|
||||
LLNotifications::instance().add("SetDisplayNameMismatch");
|
||||
return;
|
||||
}
|
||||
|
||||
const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes
|
||||
LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8);
|
||||
if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH)
|
||||
{
|
||||
LLSD args;
|
||||
args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH);
|
||||
LLNotifications::instance().add("SetDisplayNameFailedLength", args);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LLAvatarNameCache::useDisplayNames())
|
||||
{
|
||||
LLViewerDisplayName::set(display_name_utf8,
|
||||
boost::bind(&LLFloaterDisplayName::onCacheSetName, self, _1, _2, _3));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotifications::instance().add("SetDisplayNameFailedGeneric");
|
||||
}
|
||||
|
||||
self->setVisible(false);
|
||||
}
|
||||
|
||||
52
indra/newview/llfloaterdisplayname.h
Normal file
52
indra/newview/llfloaterdisplayname.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file llfloaterdisplayname.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLFLOATERDISPLAYNAME_H
|
||||
#define LLFLOATERDISPLAYNAME_H
|
||||
|
||||
|
||||
class LLFloaterDisplayName : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLFloaterDisplayName();
|
||||
virtual ~LLFloaterDisplayName();
|
||||
/*virtual*/ BOOL postBuild();
|
||||
static void onSave(void* data);
|
||||
static void onReset(void* data);
|
||||
static void onCancel(void* data);
|
||||
static void show();
|
||||
/*virtual*/ void onOpen();
|
||||
private:
|
||||
|
||||
void onCacheSetName(bool success,
|
||||
const std::string& reason,
|
||||
const LLSD& content);
|
||||
protected:
|
||||
static LLFloaterDisplayName* sInstance;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
#include "llnameeditor.h"
|
||||
#include "llcachename.h"
|
||||
#include "llavatarname.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llagent.h"
|
||||
|
||||
#include "llfontgl.h"
|
||||
@@ -82,6 +84,11 @@ LLNameEditor::~LLNameEditor()
|
||||
LLNameEditor::sInstances.erase(this);
|
||||
}
|
||||
|
||||
void LLNameEditor::on_avatar_name_response(const LLUUID& agent_id, const LLAvatarName& av_name, void *userdata){
|
||||
LLNameEditor* self = (LLNameEditor*)userdata;
|
||||
if(self->mNameID == agent_id) self->setText(av_name.getCompleteName());
|
||||
}
|
||||
|
||||
void LLNameEditor::setNameID(const LLUUID& name_id, BOOL is_group)
|
||||
{
|
||||
mNameID = name_id;
|
||||
@@ -90,7 +97,21 @@ void LLNameEditor::setNameID(const LLUUID& name_id, BOOL is_group)
|
||||
|
||||
if (!is_group)
|
||||
{
|
||||
gCacheName->getFullName(name_id, name);
|
||||
/* Phoenix: Wolfspirit: Check if we already have the name in Cache.
|
||||
This will (if DN is enabled) return the full name (Displayname (username)).
|
||||
If DN is diabled it will return the old "Firstname Lastname" style.
|
||||
If it is not in cache, then add the LegacyName until we received the name from the callback.
|
||||
Do the Request only, if DN is enabled. */
|
||||
|
||||
LLAvatarName av_name;
|
||||
if(LLAvatarNameCache::get(name_id, &av_name)){
|
||||
name = av_name.getCompleteName();
|
||||
}
|
||||
else
|
||||
{
|
||||
gCacheName->getFullName(name_id,name);
|
||||
if(LLAvatarNameCache::useDisplayNames()) LLAvatarNameCache::get(name_id, boost::bind(&LLNameEditor::on_avatar_name_response, _1, _2, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -108,7 +129,16 @@ void LLNameEditor::refresh(const LLUUID& id, const std::string& firstname,
|
||||
std::string name;
|
||||
if (!is_group)
|
||||
{
|
||||
name = firstname + " " + lastname;
|
||||
/* Phoenix: Wolfspirit: Use DN Cache first */
|
||||
LLAvatarName av_name;
|
||||
if(LLAvatarNameCache::get(id, &av_name)){
|
||||
name = av_name.getCompleteName();
|
||||
}
|
||||
else
|
||||
{
|
||||
gCacheName->getFullName(id,name);
|
||||
if(LLAvatarNameCache::useDisplayNames()) LLAvatarNameCache::get(id, boost::bind(&LLNameEditor::on_avatar_name_response, _1, _2, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "llstring.h"
|
||||
#include "llfontgl.h"
|
||||
#include "lllineeditor.h"
|
||||
#include "llavatarname.h"
|
||||
|
||||
|
||||
class LLNameEditor
|
||||
@@ -79,6 +80,7 @@ public:
|
||||
|
||||
private:
|
||||
static std::set<LLNameEditor*> sInstances;
|
||||
static void on_avatar_name_response(const LLUUID& agent_id, const LLAvatarName& av_name, void *userdata);
|
||||
|
||||
private:
|
||||
LLUUID mNameID;
|
||||
|
||||
@@ -83,15 +83,13 @@
|
||||
#include "roles_constants.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewermenu.h"
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
@@ -1416,9 +1414,11 @@ void LLPanelAvatar::setAvatar(LLViewerObject *avatarp)
|
||||
{
|
||||
name.assign("");
|
||||
}
|
||||
LLAvatarName av_name;
|
||||
LLAvatarNameCache::get(avatarp->getID(), &av_name);
|
||||
|
||||
// If we have an avatar pointer, they must be online.
|
||||
setAvatarID(avatarp->getID(), name, ONLINE_STATUS_YES);
|
||||
setAvatarID(avatarp->getID(), av_name.getCompleteName(), ONLINE_STATUS_YES);
|
||||
}
|
||||
|
||||
void LLPanelAvatar::onCommitKey(LLUICtrl* ctrl, void* data)
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llvoavatar.h"
|
||||
|
||||
LLPanelGeneral::LLPanelGeneral()
|
||||
{
|
||||
@@ -55,6 +57,9 @@ BOOL LLPanelGeneral::postBuild()
|
||||
LLComboBox* fade_out_combobox = getChild<LLComboBox>("fade_out_combobox");
|
||||
fade_out_combobox->setCurrentByIndex(gSavedSettings.getS32("RenderName"));
|
||||
|
||||
LLComboBox* namesystem_combobox = getChild<LLComboBox>("namesystem_combobox");
|
||||
namesystem_combobox->setCurrentByIndex(gSavedSettings.getS32("PhoenixNameSystem"));
|
||||
|
||||
childSetValue("default_start_location", gSavedSettings.getBOOL("LoginLastLocation") ? "MyLastLocation" : "MyHome");
|
||||
childSetValue("show_location_checkbox", gSavedSettings.getBOOL("ShowStartLocation"));
|
||||
childSetValue("show_all_title_checkbox", gSavedSettings.getBOOL("RenderHideGroupTitleAll"));
|
||||
@@ -117,6 +122,16 @@ void LLPanelGeneral::apply()
|
||||
LLComboBox* fade_out_combobox = getChild<LLComboBox>("fade_out_combobox");
|
||||
gSavedSettings.setS32("RenderName", fade_out_combobox->getCurrentIndex());
|
||||
|
||||
LLComboBox* namesystem_combobox = getChild<LLComboBox>("namesystem_combobox");
|
||||
if(gSavedSettings.getS32("PhoenixNameSystem")!=namesystem_combobox->getCurrentIndex()){
|
||||
gSavedSettings.setS32("PhoenixNameSystem", namesystem_combobox->getCurrentIndex());
|
||||
if(gAgent.getRegion()){
|
||||
if(namesystem_combobox->getCurrentIndex()<=0 || namesystem_combobox->getCurrentIndex()>2) LLAvatarNameCache::setUseDisplayNames(false);
|
||||
else LLAvatarNameCache::setUseDisplayNames(true);
|
||||
//LLVOAvatar::invalidateNameTags(); No need, they'll be updated on the next loop
|
||||
}
|
||||
}
|
||||
|
||||
gSavedSettings.setBOOL("LoginLastLocation", childGetValue("default_start_location").asString() == "MyLastLocation");
|
||||
gSavedSettings.setBOOL("ShowStartLocation", childGetValue("show_location_checkbox"));
|
||||
gSavedSettings.setBOOL("RenderHideGroupTitleAll", childGetValue("show_all_title_checkbox"));
|
||||
|
||||
@@ -205,6 +205,8 @@
|
||||
#include "scriptcounter.h"
|
||||
// </edit>
|
||||
|
||||
#include "llavatarnamecache.h"
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
@@ -2700,6 +2702,13 @@ bool idle_startup()
|
||||
LLAppViewer::instance()->loadNameCache();
|
||||
}
|
||||
|
||||
// Start cache in not-running state until we figure out if we have
|
||||
// capabilities for display name lookup
|
||||
LLAvatarNameCache::initClass(false);
|
||||
S32 phoenix_name_system = gSavedSettings.getS32("PhoenixNameSystem");
|
||||
if(phoenix_name_system <= 0 || phoenix_name_system > 2) LLAvatarNameCache::setUseDisplayNames(false);
|
||||
else LLAvatarNameCache::setUseDisplayNames(true);
|
||||
|
||||
// *Note: this is where gWorldMap used to be initialized.
|
||||
|
||||
// register null callbacks for audio until the audio system is initialized
|
||||
|
||||
212
indra/newview/llviewerdisplayname.cpp
Normal file
212
indra/newview/llviewerdisplayname.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @file llviewerdisplayname.cpp
|
||||
* @brief Wrapper for display name functionality
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
/*
|
||||
Ported to Phoenix by Wolfspirit Magic.
|
||||
*/
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llviewerdisplayname.h"
|
||||
|
||||
// viewer includes
|
||||
#include "llagent.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llvoavatar.h"
|
||||
|
||||
// library includes
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llhttpnode.h"
|
||||
#include "llnotifications.h"
|
||||
#include "llui.h" // getLanguage()
|
||||
|
||||
namespace LLViewerDisplayName
|
||||
{
|
||||
// Fired when viewer receives server response to display name change
|
||||
set_name_signal_t sSetDisplayNameSignal;
|
||||
|
||||
// Fired when there is a change in the agent's name
|
||||
name_changed_signal_t sNameChangedSignal;
|
||||
|
||||
void addNameChangedCallback(const name_changed_signal_t::slot_type& cb)
|
||||
{
|
||||
sNameChangedSignal.connect(cb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LLSetDisplayNameResponder : public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
// only care about errors
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());
|
||||
LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
|
||||
}
|
||||
};
|
||||
|
||||
void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot)
|
||||
{
|
||||
// TODO: simple validation here
|
||||
|
||||
LLViewerRegion* region = gAgent.getRegion();
|
||||
llassert(region);
|
||||
std::string cap_url = region->getCapability("SetDisplayName");
|
||||
if (cap_url.empty())
|
||||
{
|
||||
// this server does not support display names, report error
|
||||
slot(false, "unsupported", LLSD());
|
||||
return;
|
||||
}
|
||||
|
||||
// People API can return localized error messages. Indicate our
|
||||
// language preference via header.
|
||||
LLSD headers;
|
||||
headers["Accept-Language"] = LLUI::getLanguage();
|
||||
|
||||
// People API requires both the old and new value to change a variable.
|
||||
// Our display name will be in cache before the viewer's UI is available
|
||||
// to request a change, so we can use direct lookup without callback.
|
||||
LLAvatarName av_name;
|
||||
if (!LLAvatarNameCache::get( gAgent.getID(), &av_name))
|
||||
{
|
||||
slot(false, "name unavailable", LLSD());
|
||||
return;
|
||||
}
|
||||
|
||||
// People API expects array of [ "old value", "new value" ]
|
||||
LLSD change_array = LLSD::emptyArray();
|
||||
change_array.append(av_name.mDisplayName);
|
||||
change_array.append(display_name);
|
||||
|
||||
llinfos << "Set name POST to " << cap_url << llendl;
|
||||
|
||||
// Record our caller for when the server sends back a reply
|
||||
sSetDisplayNameSignal.connect(slot);
|
||||
|
||||
// POST the requested change. The sim will not send a response back to
|
||||
// this request directly, rather it will send a separate message after it
|
||||
// communicates with the back-end.
|
||||
LLSD body;
|
||||
body["display_name"] = change_array;
|
||||
LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers);
|
||||
}
|
||||
|
||||
class LLSetDisplayNameReply : public LLHTTPNode
|
||||
{
|
||||
LOG_CLASS(LLSetDisplayNameReply);
|
||||
public:
|
||||
/*virtual*/ void post(
|
||||
LLHTTPNode::ResponsePtr response,
|
||||
const LLSD& context,
|
||||
const LLSD& input) const
|
||||
{
|
||||
LLSD body = input["body"];
|
||||
|
||||
S32 status = body["status"].asInteger();
|
||||
bool success = (status == 200);
|
||||
std::string reason = body["reason"].asString();
|
||||
LLSD content = body["content"];
|
||||
|
||||
llinfos << "status " << status << " reason " << reason << llendl;
|
||||
|
||||
// If viewer's concept of display name is out-of-date, the set request
|
||||
// will fail with 409 Conflict. If that happens, fetch up-to-date
|
||||
// name information.
|
||||
if (status == 409)
|
||||
{
|
||||
LLUUID agent_id = gAgent.getID();
|
||||
// Flush stale data
|
||||
LLAvatarNameCache::erase( agent_id );
|
||||
// Queue request for new data
|
||||
LLAvatarName ignored;
|
||||
LLAvatarNameCache::get( agent_id, &ignored );
|
||||
// Kill name tag, as it is wrong
|
||||
LLVOAvatar::invalidateNameTag( agent_id );
|
||||
}
|
||||
|
||||
// inform caller of result
|
||||
LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content);
|
||||
LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class LLDisplayNameUpdate : public LLHTTPNode
|
||||
{
|
||||
|
||||
/*virtual*/ void post(
|
||||
LLHTTPNode::ResponsePtr response,
|
||||
const LLSD& context,
|
||||
const LLSD& input) const
|
||||
{
|
||||
LLSD body = input["body"];
|
||||
LLUUID agent_id = body["agent_id"];
|
||||
std::string old_display_name = body["old_display_name"];
|
||||
// By convention this record is called "agent" in the People API
|
||||
LLSD name_data = body["agent"];
|
||||
|
||||
// Inject the new name data into cache
|
||||
LLAvatarName av_name;
|
||||
av_name.fromLLSD( name_data );
|
||||
|
||||
llinfos << "name-update now " << LLDate::now()
|
||||
<< " next_update " << LLDate(av_name.mNextUpdate)
|
||||
<< llendl;
|
||||
|
||||
// Name expiration time may be provided in headers, or we may use a
|
||||
// default value
|
||||
// *TODO: get actual headers out of ResponsePtr
|
||||
//LLSD headers = response->mHeaders;
|
||||
LLSD headers;
|
||||
av_name.mExpires =
|
||||
LLAvatarNameCache::nameExpirationFromHeaders(headers);
|
||||
|
||||
LLAvatarNameCache::insert(agent_id, av_name);
|
||||
|
||||
// force name tag to update
|
||||
LLVOAvatar::invalidateNameTag(agent_id);
|
||||
|
||||
LLSD args;
|
||||
args["OLD_NAME"] = old_display_name;
|
||||
args["SLID"] = av_name.mUsername;
|
||||
args["NEW_NAME"] = av_name.mDisplayName;
|
||||
LLNotifications::instance().add("DisplayNameUpdate", args);
|
||||
if (agent_id == gAgent.getID())
|
||||
{
|
||||
LLViewerDisplayName::sNameChangedSignal();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LLHTTPRegistration<LLSetDisplayNameReply>
|
||||
gHTTPRegistrationMessageSetDisplayNameReply(
|
||||
"/message/SetDisplayNameReply");
|
||||
|
||||
LLHTTPRegistration<LLDisplayNameUpdate>
|
||||
gHTTPRegistrationMessageDisplayNameUpdate(
|
||||
"/message/DisplayNameUpdate");
|
||||
|
||||
55
indra/newview/llviewerdisplayname.h
Normal file
55
indra/newview/llviewerdisplayname.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @file llviewerdisplayname.h
|
||||
* @brief Wrapper for display name functionality
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
/*
|
||||
Ported to Phoenix by Wolfspirit Magic.
|
||||
*/
|
||||
#ifndef LLVIEWERDISPLAYNAME_H
|
||||
#define LLVIEWERDISPLAYNAME_H
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLSD;
|
||||
class LLUUID;
|
||||
|
||||
namespace LLViewerDisplayName
|
||||
{
|
||||
typedef boost::signals2::signal<
|
||||
void (bool success, const std::string& reason, const LLSD& content)>
|
||||
set_name_signal_t;
|
||||
typedef set_name_signal_t::slot_type set_name_slot_t;
|
||||
|
||||
typedef boost::signals2::signal<void (void)> name_changed_signal_t;
|
||||
typedef name_changed_signal_t::slot_type name_changed_slot_t;
|
||||
|
||||
// Sends an update to the server to change a display name
|
||||
// and call back when done. May not succeed due to service
|
||||
// unavailable or name not available.
|
||||
void set(const std::string& display_name, const set_name_slot_t& slot);
|
||||
|
||||
void addNameChangedCallback(const name_changed_signal_t::slot_type& cb);
|
||||
}
|
||||
|
||||
#endif // LLVIEWERDISPLAYNAME_H
|
||||
@@ -250,6 +250,7 @@
|
||||
// </edit>
|
||||
|
||||
#include "scriptcounter.h"
|
||||
#include "llfloaterdisplayname.h"
|
||||
|
||||
using namespace LLVOAvatarDefines;
|
||||
void init_client_menu(LLMenuGL* menu);
|
||||
@@ -6444,6 +6445,11 @@ class LLShowFloater : public view_listener_t
|
||||
gAgent.changeCameraToCustomizeAvatar();
|
||||
}
|
||||
}
|
||||
// Phoenix: Wolfspirit: Enabled Show Floater out of viewer menu
|
||||
else if (floater_name == "displayname")
|
||||
{
|
||||
LLFloaterDisplayName::show();
|
||||
}
|
||||
else if (floater_name == "friends")
|
||||
{
|
||||
LLFloaterMyFriends::toggleInstance(0);
|
||||
|
||||
@@ -126,6 +126,8 @@ public:
|
||||
mRegion->showReleaseNotes();
|
||||
}
|
||||
}
|
||||
|
||||
mRegion->setCapabilitiesReceived(true);
|
||||
|
||||
if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
|
||||
{
|
||||
@@ -1455,6 +1457,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
|
||||
capabilityNames.append("FetchLibDescendents");
|
||||
capabilityNames.append("GetTexture");
|
||||
capabilityNames.append("GroupProposalBallot");
|
||||
capabilityNames.append("GetDisplayNames");
|
||||
capabilityNames.append("HomeLocation");
|
||||
capabilityNames.append("MapLayer");
|
||||
capabilityNames.append("MapLayerGod");
|
||||
@@ -1472,6 +1475,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
|
||||
capabilityNames.append("SendPostcard");
|
||||
capabilityNames.append("SendUserReport");
|
||||
capabilityNames.append("SendUserReportWithScreenshot");
|
||||
capabilityNames.append("SetDisplayName");
|
||||
capabilityNames.append("ServerReleaseNotes");
|
||||
capabilityNames.append("StartGroupProposal");
|
||||
capabilityNames.append("TextureStats");
|
||||
@@ -1533,6 +1537,16 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool LLViewerRegion::capabilitiesReceived() const
|
||||
{
|
||||
return mCapabilitiesReceived;
|
||||
}
|
||||
|
||||
void LLViewerRegion::setCapabilitiesReceived(bool received)
|
||||
{
|
||||
mCapabilitiesReceived = received;
|
||||
}
|
||||
|
||||
void LLViewerRegion::logActiveCapabilities() const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
@@ -230,6 +230,9 @@ public:
|
||||
std::string getCapability(const std::string& name) const;
|
||||
static bool isSpecialCapabilityName(const std::string &name);
|
||||
void logActiveCapabilities() const;
|
||||
// has region received its final (not seed) capability list?
|
||||
bool capabilitiesReceived() const;
|
||||
void setCapabilitiesReceived(bool received);
|
||||
|
||||
const LLHost &getHost() const { return mHost; }
|
||||
const U64 &getHandle() const { return mHandle; }
|
||||
@@ -397,6 +400,7 @@ private:
|
||||
|
||||
private:
|
||||
bool mAlive; // can become false if circuit disconnects
|
||||
bool mCapabilitiesReceived;
|
||||
|
||||
//spatial partitions for objects in this region
|
||||
std::vector<LLSpatialPartition*> mObjectPartition;
|
||||
|
||||
@@ -97,6 +97,9 @@
|
||||
#include "llimagemetadatareader.h"
|
||||
// </edit>
|
||||
|
||||
#include "llavatarname.h"
|
||||
#include "llavatarnamecache.h"
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
@@ -758,6 +761,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
|
||||
mAppearanceAnimating(FALSE),
|
||||
mNameString(),
|
||||
mTitle(),
|
||||
mRenderedName(),
|
||||
mUsedNameSystem(),
|
||||
mClientName(),
|
||||
mNameAway(FALSE),
|
||||
mNameBusy(FALSE),
|
||||
mNameMute(FALSE),
|
||||
@@ -3513,6 +3519,8 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
mVisibleChat = visible_chat;
|
||||
new_name = TRUE;
|
||||
}
|
||||
|
||||
static LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
|
||||
|
||||
// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b
|
||||
if (fRlvShowNames)
|
||||
@@ -3695,6 +3703,27 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
|
||||
if (mNameText.notNull() && firstname && lastname)
|
||||
{
|
||||
/*
|
||||
Phoenix: Wolfspirit:
|
||||
The following part replaces the username with the Displayname, if Displaynames are enabled
|
||||
|
||||
*/
|
||||
LLAvatarName av_name;
|
||||
bool dnhasloaded = false;
|
||||
bool useddn = true;
|
||||
if(LLAvatarNameCache::useDisplayNames() && LLAvatarNameCache::get(getID(), &av_name)) dnhasloaded=true;
|
||||
|
||||
std::string usedname;
|
||||
if(dnhasloaded && !av_name.mIsDisplayNameDefault && !av_name.mIsDummy
|
||||
&& av_name.mDisplayName != av_name.getLegacyName()) usedname = av_name.mDisplayName;
|
||||
else {
|
||||
usedname = firstname->getString();
|
||||
usedname += " ";
|
||||
usedname += lastname->getString();
|
||||
dnhasloaded=false;
|
||||
useddn=false;
|
||||
}
|
||||
|
||||
BOOL is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end();
|
||||
if(mNameAway && ! is_away) mIdleTimer.reset();
|
||||
BOOL is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end();
|
||||
@@ -3713,11 +3742,12 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
|
||||
if (mNameString.empty() ||
|
||||
new_name ||
|
||||
mRenderedName != usedname ||
|
||||
mUsedNameSystem != phoenix_name_system ||
|
||||
(!title && !mTitle.empty()) ||
|
||||
(title && mTitle != title->getString()) ||
|
||||
(is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute)
|
||||
|| is_appearance != mNameAppearance
|
||||
|| client.length() ) // <edit/>
|
||||
|| is_appearance != mNameAppearance || client != mClientName)
|
||||
{
|
||||
std::string line;
|
||||
|
||||
@@ -3729,23 +3759,42 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
{
|
||||
// If all group titles are turned off, stack first name
|
||||
// on a line above last name
|
||||
line += firstname->getString();
|
||||
line += "\n";
|
||||
if(!dnhasloaded){
|
||||
line += firstname->getString();
|
||||
line += "\n";
|
||||
line += lastname->getString();
|
||||
}
|
||||
else
|
||||
{
|
||||
line += usedname;
|
||||
}
|
||||
}
|
||||
else if (title && title->getString() && title->getString()[0] != '\0')
|
||||
{
|
||||
line += title->getString();
|
||||
LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR);
|
||||
line += "\n";
|
||||
line += firstname->getString();
|
||||
if(!dnhasloaded){
|
||||
line += usedname;
|
||||
}
|
||||
else
|
||||
{
|
||||
useddn=true;
|
||||
line += usedname;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
line += firstname->getString();
|
||||
if(!dnhasloaded){
|
||||
line += usedname;
|
||||
}
|
||||
else
|
||||
{
|
||||
useddn=true;
|
||||
line += usedname;
|
||||
}
|
||||
}
|
||||
|
||||
line += " ";
|
||||
line += lastname->getString();
|
||||
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b
|
||||
}
|
||||
else
|
||||
@@ -3799,6 +3848,19 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
line += " (" + additions + ")";
|
||||
|
||||
}
|
||||
if(useddn){
|
||||
if(phoenix_name_system != 2){
|
||||
line += "\n";
|
||||
line += "("+av_name.mUsername+")";
|
||||
}
|
||||
mRenderedName = av_name.mDisplayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRenderedName = firstname->getString();
|
||||
mRenderedName += " ";
|
||||
mRenderedName += lastname->getString();
|
||||
}
|
||||
if (is_appearance)
|
||||
{
|
||||
line += "\n";
|
||||
@@ -3813,6 +3875,8 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
mNameAway = is_away;
|
||||
mNameBusy = is_busy;
|
||||
mNameMute = is_muted;
|
||||
mClientName = client;
|
||||
mUsedNameSystem = phoenix_name_system;
|
||||
mNameAppearance = is_appearance;
|
||||
mTitle = title ? title->getString() : "";
|
||||
LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR);
|
||||
@@ -3926,6 +3990,44 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
|
||||
}
|
||||
}
|
||||
|
||||
/* Phoenix: Wolfspirit: This allows us to replace one specific nametag of a user */
|
||||
|
||||
void LLVOAvatar::clearNameTag()
|
||||
{
|
||||
mNameString.clear();
|
||||
if (mNameText)
|
||||
{
|
||||
mNameText->setLabel("");
|
||||
mNameText->setString(mNameString);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id)
|
||||
{
|
||||
LLViewerObject* obj = gObjectList.findObject(agent_id);
|
||||
if (!obj) return;
|
||||
|
||||
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(obj);
|
||||
if (!avatar) return;
|
||||
|
||||
avatar->clearNameTag();
|
||||
}
|
||||
|
||||
//staticmNameString.empty()
|
||||
void LLVOAvatar::invalidateNameTags()
|
||||
{
|
||||
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
|
||||
iter != LLCharacter::sInstances.end(); ++iter)
|
||||
{
|
||||
LLVOAvatar* avatar = (LLVOAvatar*) *iter;
|
||||
if (!avatar) continue;
|
||||
if (avatar->isDead()) continue;
|
||||
|
||||
avatar->clearNameTag();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLVOAvatar::idleUpdateTractorBeam()
|
||||
{
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "llwearable.h"
|
||||
#include "llvoavatardefines.h"
|
||||
#include "emeraldboobutils.h"
|
||||
#include "llavatarname.h"
|
||||
|
||||
|
||||
extern const LLUUID ANIM_AGENT_BODY_NOISE;
|
||||
@@ -119,6 +120,10 @@ public:
|
||||
void idleUpdateWindEffect();
|
||||
void idleUpdateBoobEffect();
|
||||
void idleUpdateNameTag(const LLVector3& root_pos_last);
|
||||
void clearNameTag();
|
||||
static void invalidateNameTag(const LLUUID& agent_id);
|
||||
// force all name tags to rebuild, useful when display names turned on/off
|
||||
static void invalidateNameTags();
|
||||
void idleUpdateRenderCost();
|
||||
void idleUpdateTractorBeam();
|
||||
void idleUpdateBelowWater();
|
||||
@@ -505,6 +510,7 @@ private:
|
||||
std::deque<LLChat> mChats;
|
||||
BOOL mTyping;
|
||||
LLFrameTimer mTypingTimer;
|
||||
static void on_avatar_name_response(const LLUUID& agent_id, const LLAvatarName& av_name, void *userdata);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// wind rippling in clothes
|
||||
@@ -725,6 +731,9 @@ private:
|
||||
BOOL mRenderTag;
|
||||
BOOL mVisibleChat;
|
||||
BOOL mRenderGroupTitles;
|
||||
std::string mRenderedName;
|
||||
std::string mClientName;
|
||||
S32 mUsedNameSystem;
|
||||
|
||||
std::string mDebugText;
|
||||
U64 mLastRegionHandle;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater can_close="true" can_drag_on_left="false" can_minimize="false"
|
||||
can_resize="false" enabled="true" height="220"
|
||||
mouse_opaque="true" name="Display Name" title="CHANGE DISPLAY NAME" width="400">
|
||||
|
||||
<text length="1" bottom_delta="-50" font="SansSerif" height="25" left="20" text_color="AlertTextColor" name="lockout_text" visible="true" width="360"
|
||||
wrap="true">
|
||||
Next possible change: [TIME].
|
||||
</text>
|
||||
|
||||
<text left="20" bottom_delta="-20" width="360" height="18" font="SansSerif" name="set_name_label">
|
||||
New Display Name:
|
||||
</text>
|
||||
<line_editor max_length="31" name="display_name_editor" width="300" height="20" left="50" bottom_delta="-20" />
|
||||
<text left="20" bottom_delta="-25" width="360" height="18" font="SansSerif" name="name_confirm_label">
|
||||
Type your new name again to confirm:
|
||||
</text>
|
||||
<line_editor max_length="31" width="300" name="display_name_confirm" height="20" bottom_delta="-20" left="50" />
|
||||
<button height="20" bottom_delta="-28" label="Save" font="SansSerif" left="20" name="save_btn" tool_tip="Save your new Display Name" width="113" />
|
||||
<button height="20" bottom_delta="0" label="Reset" font="SansSerif" left_delta="123" name="reset_btn" tool_tip="Make Display Name the same as Username" width="113" />
|
||||
<button height="20" bottom_delta="0" label="Cancel" font="SansSerif" left_delta="123" name="cancel_btn" tool_tip="Cancel and close this Dialog" width="113" />
|
||||
<text left="20" bottom_delta="-25" width="360" height="18" font="SansSerif" name="name_confirm_label">
|
||||
The name you give your avatar is called yours Display Name.
|
||||
</text>
|
||||
<text left="20" bottom_delta="-18" width="360" height="18" font="SansSerif" name="name_confirm_label">
|
||||
You can change it once a week.
|
||||
</text>
|
||||
</floater>
|
||||
|
||||
@@ -219,6 +219,10 @@
|
||||
<on_click function="ShowFloater" userdata="appearance" />
|
||||
<on_enable function="Edit.EnableCustomizeAvatar" />
|
||||
</menu_item_call>
|
||||
<menu_item_call bottom="-362" enabled="true" height="19" label="Display Name..." left="0"
|
||||
mouse_opaque="true" name="Display Name..." width="153">
|
||||
<on_click function="ShowFloater" userdata="displayname" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator bottom="-370" enabled="true" height="8" label="-----------" left="0"
|
||||
mouse_opaque="true" name="separator7" width="153" />
|
||||
<menu_item_check bottom="-389" enabled="true" height="19" label="Friends..." left="0"
|
||||
|
||||
@@ -6688,5 +6688,88 @@ Yes
|
||||
<global name="PermNo">
|
||||
No
|
||||
</global>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SetDisplayNameSuccess"
|
||||
type="alert">
|
||||
Hi [DISPLAY_NAME]!
|
||||
|
||||
Just like in real life, it takes a while for everyone to learn about a new name. Please allow several days for [http://wiki.secondlife.com/wiki/Setting_your_display_name your name to update] in objects, scripts, search, etc.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SetDisplayNameBlocked"
|
||||
type="alert">
|
||||
Sorry, you cannot change your display name. If you feel this is in error, please contact support.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SetDisplayNameFailedLength"
|
||||
type="alertmodal">
|
||||
Sorry, that name is too long. Display names can have a maximum of [LENGTH] characters.
|
||||
|
||||
Please try a shorter name.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SetDisplayNameFailedGeneric"
|
||||
type="alertmodal">
|
||||
Sorry, we could not set your display name. Please try again later.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="SetDisplayNameMismatch"
|
||||
type="alertmodal">
|
||||
The display names you entered do not match. Please re-enter.
|
||||
</notification>
|
||||
|
||||
<!-- *NOTE: This should never happen -->
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AgentDisplayNameUpdateThresholdExceeded"
|
||||
type="alertmodal">
|
||||
Sorry, you have to wait longer before you can change your display name.
|
||||
|
||||
See http://wiki.secondlife.com/wiki/Setting_your_display_name
|
||||
|
||||
Please try again later.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AgentDisplayNameSetBlocked"
|
||||
type="alertmodal">
|
||||
Sorry, we could not set your requested name because it contains a banned word.
|
||||
|
||||
Please try a different name.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AgentDisplayNameSetInvalidUnicode"
|
||||
type="alertmodal">
|
||||
The display name you wish to set contains invalid characters.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AgentDisplayNameSetOnlyPunctuation"
|
||||
type="alertmodal">
|
||||
Your display name must contain letters other than punctuation.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="notifytip.tga"
|
||||
name="DisplayNameUpdate"
|
||||
type="notifytip">
|
||||
[OLD_NAME] ([SLID]) is now known as [NEW_NAME].
|
||||
</notification>
|
||||
|
||||
|
||||
</notifications>
|
||||
|
||||
|
||||
@@ -29,6 +29,18 @@
|
||||
Always
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<combo_box bottom_delta="0" follows="left|top" height="18" left="330"
|
||||
mouse_opaque="true" name="namesystem_combobox" width="146">
|
||||
<combo_item name="Old Names" value="Old Names">
|
||||
Old Names
|
||||
</combo_item>
|
||||
<combo_item name="Display Names (with Username)" value="Display Names (with Username)">
|
||||
Display Names (with Username)
|
||||
</combo_item>
|
||||
<combo_item name="Display Names only" value="Display Names only">
|
||||
Display Names only
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<check_box bottom_delta="-25" follows="left|top"
|
||||
font="SansSerifSmall" height="16" initial_value="true"
|
||||
label="Small Avatar Names" left="151" name="small_avatar_names_checkbox"
|
||||
|
||||
Reference in New Issue
Block a user