using System; using System.Collections.Generic; using System.Threading; using libsecondlife; using libsecondlife.Packets; namespace libsecondlife.Utilities { /// /// Keeps an up to date inventory of the currently seen objects in each /// simulator /// //public class ObjectTracker //{ // private SecondLife Client; // private Dictionary> SimPrims = new Dictionary>(); // /// // /// Default constructor // /// // /// A reference to the SecondLife client to track // /// objects for // public ObjectTracker(SecondLife client) // { // Client = client; // } //} /// /// Maintains a cache of avatars and does blocking lookups for avatar data /// public class AvatarTracker { protected SecondLife Client; protected Dictionary avatars = new Dictionary(); protected Dictionary NameLookupEvents = new Dictionary(); public AvatarTracker(SecondLife client) { Client = client; Client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames); } /// /// Check if a particular avatar is in the local cache /// /// /// public bool Contains(LLUUID id) { return avatars.ContainsKey(id); } /// /// Get an avatar's name, either from the cache or request it. /// This function is blocking /// /// Avatar key to look up /// The avatar name, or String.Empty if the lookup failed 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); } /// /// /// /// //public void BeginGetAvatarName(LLUUID id) //{ // // TODO: BeginGetAvatarNames is pretty bulky, rewrite a simple version here // List ids = new List(); // ids.Add(id); // BeginGetAvatarNames(ids); //} /// /// /// /// //public void BeginGetAvatarNames(List ids) //{ // Dictionary havenames = new Dictionary(); // List neednames = new List(); // // 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); // } //} /// /// This function will only check if the avatar name exists locally, /// it will not do any networking calls to fetch the name /// /// The avatar name, or an empty string if it's not found protected string LocalAvatarNameLookup(LLUUID id) { lock (avatars) { if (avatars.ContainsKey(id)) return avatars[id].Name; else return String.Empty; } } private void Avatars_OnAvatarNames(Dictionary names) { lock (avatars) { foreach (KeyValuePair 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(); } } } } } }