Files
libremetaverse/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
John Hurliman b3fc7de42f * Moved several stranded delegates and enums inside parent classes
* Updated the various clients to reflect the moved delegates and enums
* Redid Avatar, AvatarManager, and MainAvatar almost from the ground up
* Moved the avatar caching to AvatarTracker in libsecondlife.Utilities, AvatarManager only does lookups now
* Added support for fuzzy avatar searching through the Picker packets (alternative to directory searches)
* Added a unit test for AvatarTracker.GetAvatarName()
* Removed unused references from SLProxy
* Whitespace reformatting in ImageManager
* Renamed Tests.cs to NetworkTests.cs to reflect its contents properly

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@754 52acb1d6-8a22-11de-b505-999d5b087335
2006-12-22 15:28:33 +00:00

184 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using libsecondlife;
using libsecondlife.Packets;
namespace libsecondlife.Utilities
{
/// <summary>
/// Keeps an up to date inventory of the currently seen objects in each
/// simulator
/// </summary>
//public class ObjectTracker
//{
// private SecondLife Client;
// private Dictionary<ulong, Dictionary<uint, PrimObject>> SimPrims = new Dictionary<ulong, Dictionary<uint, PrimObject>>();
// /// <summary>
// /// Default constructor
// /// </summary>
// /// <param name="client">A reference to the SecondLife client to track
// /// objects for</param>
// public ObjectTracker(SecondLife client)
// {
// Client = client;
// }
//}
/// <summary>
/// Maintains a cache of avatars and does blocking lookups for avatar data
/// </summary>
public class AvatarTracker
{
protected SecondLife Client;
protected Dictionary<LLUUID, Avatar> avatars = new Dictionary<LLUUID,Avatar>();
protected Dictionary<LLUUID, ManualResetEvent> NameLookupEvents = new Dictionary<LLUUID, ManualResetEvent>();
public AvatarTracker(SecondLife client)
{
Client = client;
Client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);
}
/// <summary>
/// Check if a particular avatar is in the local cache
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool Contains(LLUUID id)
{
return avatars.ContainsKey(id);
}
/// <summary>
/// Get an avatar's name, either from the cache or request it.
/// This function is blocking
/// </summary>
/// <param name="key">Avatar key to look up</param>
/// <returns>The avatar name, or String.Empty if the lookup failed</returns>
public string GetAvatarName(LLUUID id)
{
// Short circuit the cache lookup in GetAvatarNames
if (Contains(id))
return LocalAvatarNameLookup(id);
// Add to the dictionary
lock (NameLookupEvents)
NameLookupEvents.Add(id, new ManualResetEvent(false));
// Call function
Client.Avatars.RequestAvatarName(id);
// Start blocking while we wait for this name to be fetched
NameLookupEvents[id].WaitOne(5000, false);
// Clean up
lock (NameLookupEvents)
NameLookupEvents.Remove(id);
// Return
return LocalAvatarNameLookup(id);
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
//public void BeginGetAvatarName(LLUUID id)
//{
// // TODO: BeginGetAvatarNames is pretty bulky, rewrite a simple version here
// List<LLUUID> ids = new List<LLUUID>();
// ids.Add(id);
// BeginGetAvatarNames(ids);
//}
/// <summary>
///
/// </summary>
/// <param name="ids"></param>
//public void BeginGetAvatarNames(List<LLUUID> ids)
//{
// Dictionary<LLUUID, string> havenames = new Dictionary<LLUUID, string>();
// List<LLUUID> neednames = new List<LLUUID>();
// // Fire callbacks for the ones we already have cached
// foreach (LLUUID id in ids)
// {
// if (Avatars.ContainsKey(id))
// {
// havenames[id] = Avatars[id].Name;
// //Short circuit the lookup process
// if (ManualResetEvents.ContainsKey(id))
// {
// ManualResetEvents[id].Set();
// return;
// }
// }
// else
// {
// neednames.Add(id);
// }
// }
// if (havenames.Count > 0 && OnAgentNames != null)
// {
// OnAgentNames(havenames);
// }
// if (neednames.Count > 0)
// {
// UUIDNameRequestPacket request = new UUIDNameRequestPacket();
// request.UUIDNameBlock = new UUIDNameRequestPacket.UUIDNameBlockBlock[neednames.Count];
// for (int i = 0; i < neednames.Count; i++)
// {
// request.UUIDNameBlock[i] = new UUIDNameRequestPacket.UUIDNameBlockBlock();
// request.UUIDNameBlock[i].ID = neednames[i];
// }
// Client.Network.SendPacket(request);
// }
//}
/// <summary>
/// This function will only check if the avatar name exists locally,
/// it will not do any networking calls to fetch the name
/// </summary>
/// <returns>The avatar name, or an empty string if it's not found</returns>
protected string LocalAvatarNameLookup(LLUUID id)
{
lock (avatars)
{
if (avatars.ContainsKey(id))
return avatars[id].Name;
else
return String.Empty;
}
}
private void Avatars_OnAvatarNames(Dictionary<LLUUID, string> names)
{
lock (avatars)
{
foreach (KeyValuePair<LLUUID, string> kvp in names)
{
if (!avatars.ContainsKey(kvp.Key) || avatars[kvp.Key] == null)
avatars[kvp.Key] = new Avatar();
avatars[kvp.Key].Name = kvp.Value;
lock (NameLookupEvents)
{
if (NameLookupEvents.ContainsKey(kvp.Key))
NameLookupEvents[kvp.Key].Set();
}
}
}
}
}
}