LIBOMV-868: Added support for Display Names functionality

TODO:
 * Add support for setting a display Name
 * Figure out what to do with big request (> 90 names)

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@3468 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
Latif Khalifa
2010-11-19 16:59:46 +00:00
parent 3cc85a6ddc
commit ff6ae318fc
3 changed files with 386 additions and 3 deletions

View File

@@ -25,16 +25,93 @@
*/
using System;
using System.Text;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using OpenMetaverse.Http;
using OpenMetaverse.Packets;
using OpenMetaverse.Interfaces;
using OpenMetaverse.Messages.Linden;
using OpenMetaverse.StructuredData;
namespace OpenMetaverse
{
/// <summary> Information about agents display name </summary>
public struct AgentDisplayName
{
/// <summary> Agent UUID </summary>
public UUID ID;
/// <summary> Username </summary>
public string UserName;
/// <summary> Display name </summary>
public string DisplayName;
/// <summary> First name (legacy) </summary>
public string LegacyFirstName;
/// <summary> Last name (legacy) </summary>
public string LegacyLastName;
/// <summary> Full name (legacy) </summary>
public string LegacyFullName { get { return string.Format("{0} {1}", LegacyFirstName, LegacyLastName); }}
/// <summary> Is display name default display name </summary>
public bool IsDefaultDisplayName;
/// <summary> Cache display name until </summary>
public DateTime NextUpdate;
/// <summary>
/// Creates AgentDisplayName object from OSD
/// </summary>
/// <param name="data">Incoming OSD data</param>
/// <returns>AgentDisplayName object</returns>
public static AgentDisplayName FromOSD(OSD data)
{
AgentDisplayName ret = new AgentDisplayName();
OSDMap map = (OSDMap)data;
ret.ID = map["id"];
ret.UserName = map["username"];
ret.DisplayName = map["display_name"];
ret.LegacyFirstName = map["legacy_first_name"];
ret.LegacyLastName = map["legacy_last_name"];
ret.IsDefaultDisplayName = map["is_display_name_default"];
ret.NextUpdate = map["display_name_next_update"];
return ret;
}
/// <summary>
/// Return object as OSD map
/// </summary>
/// <returns>OSD containing agent's display name data</returns>
public OSD GetOSD()
{
OSDMap map = new OSDMap();
map["id"] = ID;
map["username"] = UserName;
map["display_name"] = DisplayName;
map["legacy_first_name"] = LegacyFirstName;
map["legacy_last_name"] = LegacyLastName;
map["is_display_name_default"] = IsDefaultDisplayName;
map["display_name_next_update"] = NextUpdate;
return map;
}
public override string ToString()
{
return Helpers.StructToString(this);
//StringBuilder result = new StringBuilder();
//result.AppendLine();
//result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, "ID", ID, "UUID");
//result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, "UserName", UserName, "string");
//result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, "DisplayName", DisplayName, "string");
//result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, "LegacyFirstName", LegacyFirstName, "string");
//result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, "LegaacyLastName", LegaacyLastName, "string");
//result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, "IsDefaultDisplayName", IsDefaultDisplayName, "bool");
//result.AppendFormat("{0, 30}: {1,-40} [{2}]", "NextUpdate", NextUpdate, "DateTime");
//return result.ToString();
}
}
#region Structs
/// <summary>
/// Holds group information for Avatars such as those you might find in a profile
@@ -114,6 +191,7 @@ namespace OpenMetaverse
{
const int MAX_UUIDS_PER_PACKET = 100;
#region Events
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler<AvatarAnimationEventArgs> m_AvatarAnimation;
@@ -450,6 +528,32 @@ namespace OpenMetaverse
remove { lock (m_ClassifiedInfoReplyLock) { m_ClassifiedInfoReply -= value; } }
}
/// <summary>The event subscribers, null of no subscribers</summary>
private EventHandler<DisplayNameUpdateEventArgs> m_DisplayNameUpdate;
///<summary>Raises the DisplayNameUpdate Event</summary>
/// <param name="e">A DisplayNameUpdateEventArgs object containing
/// the data sent from the simulator</param>
protected virtual void OnDisplayNameUpdate(DisplayNameUpdateEventArgs e)
{
EventHandler<DisplayNameUpdateEventArgs> handler = m_DisplayNameUpdate;
if (handler != null)
handler(this, e);
}
/// <summary>Thread sync lock object</summary>
private readonly object m_DisplayNameUpdateLock = new object();
/// <summary>Raised when the simulator sends us data containing
/// the details of display name change</summary>
public event EventHandler<DisplayNameUpdateEventArgs> DisplayNameUpdate
{
add { lock (m_DisplayNameUpdateLock) { m_DisplayNameUpdate += value; } }
remove { lock (m_DisplayNameUpdateLock) { m_DisplayNameUpdate -= value; } }
}
#endregion Events
private GridClient Client;
/// <summary>
@@ -488,6 +592,8 @@ namespace OpenMetaverse
// Classifieds callbacks
Client.Network.RegisterCallback(PacketType.AvatarClassifiedReply, AvatarClassifiedReplyHandler);
Client.Network.RegisterCallback(PacketType.ClassifiedInfoReply, ClassifiedInfoReplyHandler);
Client.Network.RegisterEventCallback("DisplayNameUpdate", DisplayNameUpdateMessageHandler);
}
/// <summary>Tracks the specified avatar on your map</summary>
@@ -557,6 +663,68 @@ namespace OpenMetaverse
}
}
/// <summary>
/// Check if Display Names functionality is available
/// </summary>
/// <returns>True if Display name functionality is available</returns>
public bool DisplayNamesAvailable()
{
return (Client.Network.CurrentSim != null && Client.Network.CurrentSim.Caps != null) && Client.Network.CurrentSim.Caps.CapabilityURI("GetDisplayNames") != null;
}
/// <summary>
/// Callback giving results when fetching display names
/// </summary>
/// <param name="success">If the request was successful</param>
/// <param name="names">Array of display names</param>
/// <param name="badIDs">Array of UUIDs that could not be fetched</param>
public delegate void DisplayNamesCallback(bool success, AgentDisplayName[] names, UUID[] badIDs);
/// <summary>
/// Request retrieval of display names
/// </summary>
/// <param name="ids">List of UUIDs to lookup</param>
/// <param name="callback">Callback to report result of the operation</param>
public void GetDisplayNames(List<UUID> ids, DisplayNamesCallback callback)
{
if (!DisplayNamesAvailable() || ids.Count == 0)
{
callback(false, null, null);
}
StringBuilder query = new StringBuilder();
for (int i = 0; i < ids.Count && i < 90; i++)
{
query.AppendFormat("ids={0}", ids[i]);
if (i < ids.Count - 1)
{
query.Append("&");
}
}
Uri uri = new Uri(Client.Network.CurrentSim.Caps.CapabilityURI("GetDisplayNames").AbsoluteUri + "/?" + query);
CapsClient cap = new CapsClient(uri);
cap.OnComplete += (CapsClient client, OSD result, Exception error) =>
{
try
{
if (error != null)
throw error;
GetDisplayNamesMessage msg = new GetDisplayNamesMessage();
msg.Deserialize((OSDMap) result);
callback(true, msg.Agents, msg.BadIDs);
}
catch (Exception ex)
{
Logger.Log("Failed to call GetDisplayNames capability: ",
Helpers.LogLevel.Warning, Client, ex);
callback(false, null, null);
}
};
cap.BeginGetResponse(null, String.Empty, Client.Settings.CAPS_TIMEOUT);
}
/// <summary>
/// Start a request for Avatar Properties
/// </summary>
@@ -832,6 +1000,21 @@ namespace OpenMetaverse
}
}
/// <summary>
/// EQ Message fired when someone nearby changes their display name
/// </summary>
/// <param name="capsKey">The message key</param>
/// <param name="message">the IMessage object containing the deserialized data sent from the simulator</param>
/// <param name="simulator">The <see cref="Simulator"/> which originated the packet</param>
protected void DisplayNameUpdateMessageHandler(string capsKey, IMessage message, Simulator simulator)
{
if (m_DisplayNameUpdate != null)
{
DisplayNameUpdateMessage msg = (DisplayNameUpdateMessage) message;
OnDisplayNameUpdate(new DisplayNameUpdateEventArgs(msg.OldDisplayName, msg.DisplayName));
}
}
/// <summary>
/// Crossed region handler for message that comes across the EventQueue. Sent to an agent
/// when the agent crosses a sim border into a new region.
@@ -849,7 +1032,7 @@ namespace OpenMetaverse
avatarGroup.AcceptNotices = msg.GroupDataBlock[i].AcceptNotices;
avatarGroup.GroupID = msg.GroupDataBlock[i].GroupID;
avatarGroup.GroupInsigniaID = msg.GroupDataBlock[i].GroupInsigniaID;
avatarGroup.GroupName = msg.GroupDataBlock[i].GroupName;
avatarGroup.GroupName = msg.GroupDataBlock[i].GroupName;
avatarGroup.GroupPowers = msg.GroupDataBlock[i].GroupPowers;
avatarGroup.ListInProfile = msg.NewGroupDataBlock[i].ListInProfile;
@@ -1473,5 +1656,23 @@ namespace OpenMetaverse
this.m_EffectID = id;
}
}
/// <summary>
/// Event args class for display name notification messages
/// </summary>
public class DisplayNameUpdateEventArgs : EventArgs
{
private string oldDisplayName;
private AgentDisplayName displayName;
public string OldDisplayName { get { return oldDisplayName; }}
public AgentDisplayName DisplayName { get { return displayName; } }
public DisplayNameUpdateEventArgs(string oldDisplayName, AgentDisplayName displayName)
{
this.oldDisplayName = oldDisplayName;
this.displayName = displayName;
}
}
#endregion
}

View File

@@ -4767,4 +4767,182 @@ namespace OpenMetaverse.Messages.Linden
}
#endregion Resource usage
#region Display names
/// <summary>
/// Reply to request for bunch if display names
/// </summary>
public class GetDisplayNamesMessage : IMessage
{
/// <summary> Current display name </summary>
public AgentDisplayName[] Agents = new AgentDisplayName[0];
/// <summary> Following UUIDs failed to return a valid display name </summary>
public UUID[] BadIDs = new UUID[0];
/// <summary>
/// Serializes the message
/// </summary>
/// <returns>OSD containting the messaage</returns>
public OSDMap Serialize()
{
OSDArray agents = new OSDArray();
if (Agents != null && Agents.Length > 0)
{
for (int i=0; i<Agents.Length; i++)
{
agents.Add(Agents[i].GetOSD());
}
}
OSDArray badIDs = new OSDArray();
if (BadIDs != null && BadIDs.Length > 0)
{
for (int i=0; i<BadIDs.Length; i++)
{
badIDs.Add(new OSDUUID(BadIDs[i]));
}
}
OSDMap ret = new OSDMap();
ret["agents"] = agents;
ret["bad_ids"] = badIDs;
return ret;
}
public void Deserialize(OSDMap map)
{
if (map["agents"].Type == OSDType.Array)
{
OSDArray osdAgents = (OSDArray) map["agents"];
if (osdAgents.Count > 0)
{
Agents = new AgentDisplayName[osdAgents.Count];
for (int i = 0; i < osdAgents.Count; i++)
{
Agents[i] = AgentDisplayName.FromOSD(osdAgents[i]);
}
}
}
if (map["bad_ids"].Type == OSDType.Array)
{
OSDArray osdBadIDs = (OSDArray) map["bad_ids"];
if (osdBadIDs.Count > 0)
{
BadIDs = new UUID[osdBadIDs.Count];
for (int i=0; i<osdBadIDs.Count; i++)
{
BadIDs[i] = osdBadIDs[i];
}
}
}
}
}
/// <summary>
/// Message sent when requesting change of the display name
/// </summary>
public class SetDisplayNameMessage : IMessage
{
/// <summary> Current display name </summary>
public string OldDisplayName;
/// <summary> Desired new display name </summary>
public string NewDisplayName;
/// <summary>
/// Serializes the message
/// </summary>
/// <returns>OSD containting the messaage</returns>
public OSDMap Serialize()
{
OSDArray names = new OSDArray(2) {OldDisplayName, NewDisplayName};
OSDMap name = new OSDMap();
name["display_name"] = names;
return name;
}
public void Deserialize(OSDMap map)
{
OSDArray names = (OSDArray)map["display_name"];
OldDisplayName = names[0];
NewDisplayName = names[1];
}
}
/// <summary>
/// Message recieved in response to request to change display name
/// </summary>
public class SetDisplayNameReplyMessage : IMessage
{
/// <summary> New display name </summary>
public AgentDisplayName DisplayName;
/// <summary> String message indicating the result of the operation </summary>
public string Reason;
/// <summary> Numerical code of the result, 200 indicates success </summary>
public int Status;
/// <summary>
/// Serializes the message
/// </summary>
/// <returns>OSD containting the messaage</returns>
public OSDMap Serialize()
{
OSDMap agent = (OSDMap)DisplayName.GetOSD();
OSDMap ret = new OSDMap();
ret["content"] = agent;
ret["reason"] = Reason;
ret["status"] = Status;
return ret;
}
public void Deserialize(OSDMap map)
{
OSDMap agent = (OSDMap)map["content"];
DisplayName = AgentDisplayName.FromOSD(agent);
Reason = map["reason"];
Status = map["status"];
}
}
/// <summary>
/// Message recieved when someone nearby changes their display name
/// </summary>
public class DisplayNameUpdateMessage : IMessage
{
/// <summary> Previous display name, empty string if default </summary>
public string OldDisplayName;
/// <summary> New display name </summary>
public AgentDisplayName DisplayName;
/// <summary>
/// Serializes the message
/// </summary>
/// <returns>OSD containting the messaage</returns>
public OSDMap Serialize()
{
OSDMap agent = (OSDMap)DisplayName.GetOSD();
agent["old_display_name"] = OldDisplayName;
OSDMap ret = new OSDMap();
ret["agent"] = agent;
return ret;
}
public void Deserialize(OSDMap map)
{
OSDMap agent = (OSDMap)map["agent"];
DisplayName = AgentDisplayName.FromOSD(agent);
OldDisplayName = agent["old_display_name"];
}
}
#endregion Display names
}

View File

@@ -92,6 +92,10 @@ namespace OpenMetaverse.Messages
case "ObjectMedia": message = new ObjectMediaMessage(); break;
case "AttachmentResources": message = AttachmentResourcesMessage.GetMessageHandler(map); break;
case "LandResources": message = LandResourcesMessage.GetMessageHandler(map); break;
case "GetDisplayNames": message = new GetDisplayNamesMessage(); break;
case "SetDisplayName": message = new SetDisplayNameMessage(); break;
case "SetDisplayNameReply": message = new SetDisplayNameReplyMessage(); break;
case "DisplayNameUpdate": message = new DisplayNameUpdateMessage(); break;
//case "ProductInfoRequest": message = new ProductInfoRequestMessage(); break;
// Capabilities TODO: