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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user