git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@2061 52acb1d6-8a22-11de-b505-999d5b087335
763 lines
32 KiB
C#
763 lines
32 KiB
C#
/*
|
|
* Copyright (c) 2007-2008, openmetaverse.org
|
|
* All rights reserved.
|
|
*
|
|
* - Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* - Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
* - Neither the name of the openmetaverse.org nor the names
|
|
* of its contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using OpenMetaverse.Packets;
|
|
|
|
namespace OpenMetaverse
|
|
{
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Flags]
|
|
public enum FriendRights : int
|
|
{
|
|
/// <summary>The avatar has no rights</summary>
|
|
None = 0,
|
|
/// <summary>The avatar can see the online status of the target avatar</summary>
|
|
CanSeeOnline = 1,
|
|
/// <summary>The avatar can see the location of the target avatar on the map</summary>
|
|
CanSeeOnMap = 2,
|
|
/// <summary>The avatar can modify the ojects of the target avatar </summary>
|
|
CanModifyObjects = 4
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class holds information about an avatar in the friends list. There are two ways
|
|
/// to interface to this class. The first is through the set of boolean properties. This is the typical
|
|
/// way clients of this class will use it. The second interface is through two bitflag properties,
|
|
/// TheirFriendsRights and MyFriendsRights
|
|
/// </summary>
|
|
public class FriendInfo
|
|
{
|
|
private UUID m_id;
|
|
private string m_name;
|
|
private bool m_isOnline;
|
|
private bool m_canSeeMeOnline;
|
|
private bool m_canSeeMeOnMap;
|
|
private bool m_canModifyMyObjects;
|
|
private bool m_canSeeThemOnline;
|
|
private bool m_canSeeThemOnMap;
|
|
private bool m_canModifyTheirObjects;
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// System ID of the avatar
|
|
/// </summary>
|
|
public UUID UUID { get { return m_id; } }
|
|
|
|
/// <summary>
|
|
/// full name of the avatar
|
|
/// </summary>
|
|
public string Name
|
|
{
|
|
get { return m_name; }
|
|
set { m_name = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the avatar is online
|
|
/// </summary>
|
|
public bool IsOnline
|
|
{
|
|
get { return m_isOnline; }
|
|
set { m_isOnline = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the friend can see if I am online
|
|
/// </summary>
|
|
public bool CanSeeMeOnline
|
|
{
|
|
get { return m_canSeeMeOnline; }
|
|
set
|
|
{
|
|
m_canSeeMeOnline = value;
|
|
|
|
// if I can't see them online, then I can't see them on the map
|
|
if (!m_canSeeMeOnline)
|
|
m_canSeeMeOnMap = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the friend can see me on the map
|
|
/// </summary>
|
|
public bool CanSeeMeOnMap
|
|
{
|
|
get { return m_canSeeMeOnMap; }
|
|
set
|
|
{
|
|
// if I can't see them online, then I can't see them on the map
|
|
if (m_canSeeMeOnline)
|
|
m_canSeeMeOnMap = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the freind can modify my objects
|
|
/// </summary>
|
|
public bool CanModifyMyObjects
|
|
{
|
|
get { return m_canModifyMyObjects; }
|
|
set { m_canModifyMyObjects = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if I can see if my friend is online
|
|
/// </summary>
|
|
public bool CanSeeThemOnline { get { return m_canSeeThemOnline; } }
|
|
|
|
/// <summary>
|
|
/// True if I can see if my friend is on the map
|
|
/// </summary>
|
|
public bool CanSeeThemOnMap { get { return m_canSeeThemOnMap; } }
|
|
|
|
/// <summary>
|
|
/// True if I can modify my friend's objects
|
|
/// </summary>
|
|
public bool CanModifyTheirObjects { get { return m_canModifyTheirObjects; } }
|
|
|
|
/// <summary>
|
|
/// My friend's rights represented as bitmapped flags
|
|
/// </summary>
|
|
public FriendRights TheirFriendRights
|
|
{
|
|
get
|
|
{
|
|
FriendRights results = FriendRights.None;
|
|
if (m_canSeeMeOnline)
|
|
results |= FriendRights.CanSeeOnline;
|
|
if (m_canSeeMeOnMap)
|
|
results |= FriendRights.CanSeeOnMap;
|
|
if (m_canModifyMyObjects)
|
|
results |= FriendRights.CanModifyObjects;
|
|
|
|
return results;
|
|
}
|
|
set
|
|
{
|
|
m_canSeeMeOnline = (value & FriendRights.CanSeeOnline) != 0;
|
|
m_canSeeMeOnMap = (value & FriendRights.CanSeeOnMap) != 0;
|
|
m_canModifyMyObjects = (value & FriendRights.CanModifyObjects) != 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// My rights represented as bitmapped flags
|
|
/// </summary>
|
|
public FriendRights MyFriendRights
|
|
{
|
|
get
|
|
{
|
|
FriendRights results = FriendRights.None;
|
|
if (m_canSeeThemOnline)
|
|
results |= FriendRights.CanSeeOnline;
|
|
if (m_canSeeThemOnMap)
|
|
results |= FriendRights.CanSeeOnMap;
|
|
if (m_canModifyTheirObjects)
|
|
results |= FriendRights.CanModifyObjects;
|
|
|
|
return results;
|
|
}
|
|
set
|
|
{
|
|
m_canSeeThemOnline = (value & FriendRights.CanSeeOnline) != 0;
|
|
m_canSeeThemOnMap = (value & FriendRights.CanSeeOnMap) != 0;
|
|
m_canModifyTheirObjects = (value & FriendRights.CanModifyObjects) != 0;
|
|
}
|
|
}
|
|
|
|
#endregion Properties
|
|
|
|
/// <summary>
|
|
/// Used internally when building the initial list of friends at login time
|
|
/// </summary>
|
|
/// <param name="id">System ID of the avatar being prepesented</param>
|
|
/// <param name="theirRights">Rights the friend has to see you online and to modify your objects</param>
|
|
/// <param name="myRights">Rights you have to see your friend online and to modify their objects</param>
|
|
internal FriendInfo(UUID id, FriendRights theirRights, FriendRights myRights)
|
|
{
|
|
m_id = id;
|
|
m_canSeeMeOnline = (theirRights & FriendRights.CanSeeOnline) != 0;
|
|
m_canSeeMeOnMap = (theirRights & FriendRights.CanSeeOnMap) != 0;
|
|
m_canModifyMyObjects = (theirRights & FriendRights.CanModifyObjects) != 0;
|
|
|
|
m_canSeeThemOnline = (myRights & FriendRights.CanSeeOnline) != 0;
|
|
m_canSeeThemOnMap = (myRights & FriendRights.CanSeeOnMap) != 0;
|
|
m_canModifyTheirObjects = (myRights & FriendRights.CanModifyObjects) != 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// FriendInfo represented as a string
|
|
/// </summary>
|
|
/// <returns>A string reprentation of both my rights and my friends rights</returns>
|
|
public override string ToString()
|
|
{
|
|
if (!String.IsNullOrEmpty(m_name))
|
|
return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_name, TheirFriendRights,
|
|
MyFriendRights);
|
|
else
|
|
return String.Format("{0} (Their Rights: {1}, My Rights: {2})", m_id, TheirFriendRights,
|
|
MyFriendRights);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class is used to add and remove avatars from your friends list and to manage their permission.
|
|
/// </summary>
|
|
public class FriendsManager
|
|
{
|
|
#region Delegates
|
|
|
|
/// <summary>
|
|
/// Triggered when an avatar in your friends list comes online
|
|
/// </summary>
|
|
/// <param name="friend"> System ID of the avatar</param>
|
|
public delegate void FriendOnlineEvent(FriendInfo friend);
|
|
/// <summary>
|
|
/// Triggered when an avatar in your friends list goes offline
|
|
/// </summary>
|
|
/// <param name="friend"> System ID of the avatar</param>
|
|
public delegate void FriendOfflineEvent(FriendInfo friend);
|
|
/// <summary>
|
|
/// Triggered in response to a call to the FriendRights() method, or when a friend changes your rights
|
|
/// </summary>
|
|
/// <param name="friend"> System ID of the avatar you changed the right of</param>
|
|
public delegate void FriendRightsEvent(FriendInfo friend);
|
|
/// <summary>
|
|
/// Triggered when names on the friend list are received after the initial request upon login
|
|
/// </summary>
|
|
/// <param name="names"></param>
|
|
public delegate void FriendNamesReceived(Dictionary<UUID, string> names);
|
|
/// <summary>
|
|
/// Triggered when someone offers you friendship
|
|
/// </summary>
|
|
/// <param name="agentID">System ID of the agent offering friendship</param>
|
|
/// <param name="agentName">full name of the agent offereing friendship</param>
|
|
/// <param name="imSessionID">session ID need when accepting/declining the offer</param>
|
|
/// <returns>Return true to accept the friendship, false to deny it</returns>
|
|
public delegate void FriendshipOfferedEvent(UUID agentID, string agentName, UUID imSessionID);
|
|
/// <summary>
|
|
/// Trigger when your friendship offer has been accepted or declined
|
|
/// </summary>
|
|
/// <param name="agentID">System ID of the avatar who accepted your friendship offer</param>
|
|
/// <param name="agentName">Full name of the avatar who accepted your friendship offer</param>
|
|
/// <param name="accepted">Whether the friendship request was accepted or declined</param>
|
|
public delegate void FriendshipResponseEvent(UUID agentID, string agentName, bool accepted);
|
|
/// <summary>
|
|
/// Trigger when someone terminates your friendship.
|
|
/// </summary>
|
|
/// <param name="agentID">System ID of the avatar who terminated your friendship</param>
|
|
/// <param name="agentName">Full name of the avatar who terminated your friendship</param>
|
|
public delegate void FriendshipTerminatedEvent(UUID agentID, string agentName);
|
|
|
|
/// <summary>
|
|
/// Triggered in response to a FindFriend request
|
|
/// </summary>
|
|
/// <param name="agentID">Friends Key</param>
|
|
/// <param name="regionHandle">region handle friend is in</param>
|
|
/// <param name="location">X/Y location of friend</param>
|
|
public delegate void FriendFoundEvent(UUID agentID, ulong regionHandle, Vector3 location);
|
|
|
|
#endregion Delegates
|
|
|
|
#region Events
|
|
|
|
public event FriendNamesReceived OnFriendNamesReceived;
|
|
public event FriendOnlineEvent OnFriendOnline;
|
|
public event FriendOfflineEvent OnFriendOffline;
|
|
public event FriendRightsEvent OnFriendRights;
|
|
public event FriendshipOfferedEvent OnFriendshipOffered;
|
|
public event FriendshipResponseEvent OnFriendshipResponse;
|
|
public event FriendshipTerminatedEvent OnFriendshipTerminated;
|
|
public event FriendFoundEvent OnFriendFound;
|
|
|
|
#endregion Events
|
|
|
|
private GridClient Client;
|
|
/// <summary>
|
|
/// A dictionary of key/value pairs containing known friends of this avatar.
|
|
///
|
|
/// The Key is the <seealso cref="UUID"/> of the friend, the value is a <seealso cref="FriendInfo"/>
|
|
/// object that contains detailed information including permissions you have and have given to the friend
|
|
/// </summary>
|
|
public InternalDictionary<UUID, FriendInfo> FriendList = new InternalDictionary<UUID, FriendInfo>();
|
|
|
|
/// <summary>
|
|
/// A Dictionary of key/value pairs containing current pending frienship offers.
|
|
///
|
|
/// The key is the <seealso cref="UUID"/> of the avatar making the request,
|
|
/// the value is the <seealso cref="UUID"/> of the request which is used to accept
|
|
/// or decline the friendship offer
|
|
/// </summary>
|
|
public InternalDictionary<UUID, UUID> FriendRequests = new InternalDictionary<UUID, UUID>();
|
|
|
|
/// <summary>
|
|
/// Internal constructor
|
|
/// </summary>
|
|
/// <param name="client">A reference to the GridClient Object</param>
|
|
internal FriendsManager(GridClient client)
|
|
{
|
|
Client = client;
|
|
|
|
Client.Network.OnConnected += new NetworkManager.ConnectedCallback(Network_OnConnect);
|
|
Client.Avatars.OnAvatarNames += new AvatarManager.AvatarNamesCallback(Avatars_OnAvatarNames);
|
|
Client.Self.OnInstantMessage += new AgentManager.InstantMessageCallback(MainAvatar_InstantMessage);
|
|
|
|
Client.Network.RegisterCallback(PacketType.OnlineNotification, OnlineNotificationHandler);
|
|
Client.Network.RegisterCallback(PacketType.OfflineNotification, OfflineNotificationHandler);
|
|
Client.Network.RegisterCallback(PacketType.ChangeUserRights, ChangeUserRightsHandler);
|
|
Client.Network.RegisterCallback(PacketType.TerminateFriendship, TerminateFriendshipHandler);
|
|
Client.Network.RegisterCallback(PacketType.FindAgent, OnFindAgentReplyHandler);
|
|
|
|
Client.Network.RegisterLoginResponseCallback(new NetworkManager.LoginResponseCallback(Network_OnLoginResponse),
|
|
new string[] { "buddy-list" });
|
|
}
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Accept a friendship request
|
|
/// </summary>
|
|
/// <param name="fromAgentID">agentID of avatatar to form friendship with</param>
|
|
/// <param name="imSessionID">imSessionID of the friendship request message</param>
|
|
public void AcceptFriendship(UUID fromAgentID, UUID imSessionID)
|
|
{
|
|
UUID callingCardFolder = Client.Inventory.FindFolderForType(AssetType.CallingCard);
|
|
|
|
AcceptFriendshipPacket request = new AcceptFriendshipPacket();
|
|
request.AgentData.AgentID = Client.Self.AgentID;
|
|
request.AgentData.SessionID = Client.Self.SessionID;
|
|
request.TransactionBlock.TransactionID = imSessionID;
|
|
request.FolderData = new AcceptFriendshipPacket.FolderDataBlock[1];
|
|
request.FolderData[0] = new AcceptFriendshipPacket.FolderDataBlock();
|
|
request.FolderData[0].FolderID = callingCardFolder;
|
|
|
|
Client.Network.SendPacket(request);
|
|
|
|
FriendInfo friend = new FriendInfo(fromAgentID, FriendRights.CanSeeOnline,
|
|
FriendRights.CanSeeOnline);
|
|
lock (FriendList)
|
|
{
|
|
if(!FriendList.ContainsKey(fromAgentID)) FriendList.Add(friend.UUID, friend);
|
|
}
|
|
lock (FriendRequests) { if (FriendRequests.ContainsKey(fromAgentID)) FriendRequests.Remove(fromAgentID); }
|
|
|
|
Client.Avatars.RequestAvatarName(fromAgentID);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decline a friendship request
|
|
/// </summary>
|
|
/// <param name="fromAgentID"><seealso cref="UUID"/> of friend</param>
|
|
/// <param name="imSessionID">imSessionID of the friendship request message</param>
|
|
public void DeclineFriendship(UUID fromAgentID, UUID imSessionID)
|
|
{
|
|
DeclineFriendshipPacket request = new DeclineFriendshipPacket();
|
|
request.AgentData.AgentID = Client.Self.AgentID;
|
|
request.AgentData.SessionID = Client.Self.SessionID;
|
|
request.TransactionBlock.TransactionID = imSessionID;
|
|
Client.Network.SendPacket(request);
|
|
|
|
lock (FriendRequests) { if (FriendRequests.ContainsKey(fromAgentID)) FriendRequests.Remove(fromAgentID); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Offer friendship to an avatar.
|
|
/// </summary>
|
|
/// <param name="agentID">System ID of the avatar you are offering friendship to</param>
|
|
public void OfferFriendship(UUID agentID)
|
|
{
|
|
// HACK: folder id stored as "message"
|
|
UUID callingCardFolder = Client.Inventory.FindFolderForType(AssetType.CallingCard);
|
|
Client.Self.InstantMessage(Client.Self.Name,
|
|
agentID,
|
|
callingCardFolder.ToString(),
|
|
UUID.Random(),
|
|
InstantMessageDialog.FriendshipOffered,
|
|
InstantMessageOnline.Online,
|
|
Client.Self.SimPosition,
|
|
Client.Network.CurrentSim.ID,
|
|
new byte[0]);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Terminate a friendship with an avatar
|
|
/// </summary>
|
|
/// <param name="agentID">System ID of the avatar you are terminating the friendship with</param>
|
|
public void TerminateFriendship(UUID agentID)
|
|
{
|
|
if (FriendList.ContainsKey(agentID))
|
|
{
|
|
TerminateFriendshipPacket request = new TerminateFriendshipPacket();
|
|
request.AgentData.AgentID = Client.Self.AgentID;
|
|
request.AgentData.SessionID = Client.Self.SessionID;
|
|
request.ExBlock.OtherID = agentID;
|
|
|
|
Client.Network.SendPacket(request);
|
|
|
|
lock (FriendList)
|
|
{
|
|
if (FriendList.ContainsKey(agentID))
|
|
FriendList.Remove(agentID);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Fired when another friend terminates friendship. We need to remove them from
|
|
/// our cached list.
|
|
/// </summary>
|
|
/// <param name="packet"></param>
|
|
/// <param name="simulator"></param>
|
|
private void TerminateFriendshipHandler(Packet packet, Simulator simulator)
|
|
{
|
|
TerminateFriendshipPacket itsOver = (TerminateFriendshipPacket)packet;
|
|
string name = String.Empty;
|
|
lock (FriendList)
|
|
{
|
|
if (FriendList.ContainsKey(itsOver.ExBlock.OtherID))
|
|
{
|
|
name = FriendList[itsOver.ExBlock.OtherID].Name;
|
|
FriendList.Remove(itsOver.ExBlock.OtherID);
|
|
}
|
|
}
|
|
if (OnFriendshipTerminated != null)
|
|
{
|
|
OnFriendshipTerminated(itsOver.ExBlock.OtherID, name);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change the rights of a friend avatar.
|
|
/// </summary>
|
|
/// <param name="friendID">the <seealso cref="UUID"/> of the friend</param>
|
|
/// <param name="rights">the new rights to give the friend</param>
|
|
/// <remarks>This method will implicitly set the rights to those passed in the rights parameter.</remarks>
|
|
public void GrantRights(UUID friendID, FriendRights rights)
|
|
{
|
|
GrantUserRightsPacket request = new GrantUserRightsPacket();
|
|
request.AgentData.AgentID = Client.Self.AgentID;
|
|
request.AgentData.SessionID = Client.Self.SessionID;
|
|
request.Rights = new GrantUserRightsPacket.RightsBlock[1];
|
|
request.Rights[0] = new GrantUserRightsPacket.RightsBlock();
|
|
request.Rights[0].AgentRelated = friendID;
|
|
request.Rights[0].RelatedRights = (int)rights;
|
|
|
|
Client.Network.SendPacket(request);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use to map a friends location on the grid.
|
|
/// </summary>
|
|
/// <param name="friendID">Friends UUID to find</param>
|
|
/// <remarks><seealso cref="E:OnFriendFound"/></remarks>
|
|
public void MapFriend(UUID friendID)
|
|
{
|
|
FindAgentPacket stalk = new FindAgentPacket();
|
|
stalk.AgentBlock.Hunter = Client.Self.AgentID;
|
|
stalk.AgentBlock.Prey = friendID;
|
|
|
|
Client.Network.SendPacket(stalk);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use to track a friends movement on the grid
|
|
/// </summary>
|
|
/// <param name="friendID">Friends Key</param>
|
|
public void TrackFriend(UUID friendID)
|
|
{
|
|
TrackAgentPacket stalk = new TrackAgentPacket();
|
|
stalk.AgentData.AgentID = Client.Self.AgentID;
|
|
stalk.AgentData.SessionID = Client.Self.SessionID;
|
|
stalk.TargetData.PreyID = friendID;
|
|
|
|
Client.Network.SendPacket(stalk);
|
|
}
|
|
|
|
#endregion
|
|
#region Internal events
|
|
/// <summary>
|
|
/// Called when a connection to the SL server is established. The list of friend avatars
|
|
/// is populated from XML returned by the login server. That list contains the avatar's id
|
|
/// and right, but no names. Here is where those names are requested.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
private void Network_OnConnect(object sender)
|
|
{
|
|
List<UUID> names = new List<UUID>();
|
|
|
|
if ( FriendList.Count > 0 )
|
|
{
|
|
lock (FriendList)
|
|
{
|
|
foreach (KeyValuePair<UUID, FriendInfo> kvp in FriendList.Dictionary)
|
|
{
|
|
if (String.IsNullOrEmpty(kvp.Value.Name))
|
|
names.Add(kvp.Key);
|
|
}
|
|
}
|
|
|
|
Client.Avatars.RequestAvatarNames(names);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// This handles the asynchronous response of a RequestAvatarNames call.
|
|
/// </summary>
|
|
/// <param name="names">names cooresponding to the the list of IDs sent the the RequestAvatarNames call.</param>
|
|
private void Avatars_OnAvatarNames(Dictionary<UUID, string> names)
|
|
{
|
|
lock (FriendList)
|
|
{
|
|
Dictionary<UUID, string> newNames = new Dictionary<UUID, string>();
|
|
foreach (KeyValuePair<UUID, string> kvp in names)
|
|
{
|
|
if (FriendList.ContainsKey(kvp.Key))
|
|
{
|
|
if (FriendList[kvp.Key].Name == null)
|
|
newNames.Add(kvp.Key, names[kvp.Key]);
|
|
|
|
FriendList[kvp.Key].Name = names[kvp.Key];
|
|
}
|
|
}
|
|
if (newNames.Count > 0 && OnFriendNamesReceived != null)
|
|
{
|
|
try { OnFriendNamesReceived(newNames); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
#region Packet Handlers
|
|
|
|
/// <summary>
|
|
/// Handle notifications sent when a friends has come online.
|
|
/// </summary>
|
|
/// <param name="packet"></param>
|
|
/// <param name="simulator"></param>
|
|
private void OnlineNotificationHandler(Packet packet, Simulator simulator)
|
|
{
|
|
if (packet.Type == PacketType.OnlineNotification)
|
|
{
|
|
OnlineNotificationPacket notification = ((OnlineNotificationPacket)packet);
|
|
|
|
foreach (OnlineNotificationPacket.AgentBlockBlock block in notification.AgentBlock)
|
|
{
|
|
FriendInfo friend;
|
|
|
|
lock (FriendList)
|
|
{
|
|
if (!FriendList.ContainsKey(block.AgentID))
|
|
{
|
|
friend = new FriendInfo(block.AgentID, FriendRights.CanSeeOnline,
|
|
FriendRights.CanSeeOnline);
|
|
FriendList.Add(block.AgentID, friend);
|
|
}
|
|
else
|
|
{
|
|
friend = FriendList[block.AgentID];
|
|
}
|
|
}
|
|
|
|
bool doNotify = !friend.IsOnline;
|
|
friend.IsOnline = true;
|
|
|
|
if (OnFriendOnline != null && doNotify)
|
|
{
|
|
try { OnFriendOnline(friend); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Handle notifications sent when a friends has gone offline.
|
|
/// </summary>
|
|
/// <param name="packet"></param>
|
|
/// <param name="simulator"></param>
|
|
private void OfflineNotificationHandler(Packet packet, Simulator simulator)
|
|
{
|
|
if (packet.Type == PacketType.OfflineNotification)
|
|
{
|
|
OfflineNotificationPacket notification = ((OfflineNotificationPacket)packet);
|
|
|
|
foreach (OfflineNotificationPacket.AgentBlockBlock block in notification.AgentBlock)
|
|
{
|
|
FriendInfo friend;
|
|
|
|
lock (FriendList)
|
|
{
|
|
if (!FriendList.ContainsKey(block.AgentID))
|
|
FriendList.Add(block.AgentID, new FriendInfo(block.AgentID, FriendRights.CanSeeOnline, FriendRights.CanSeeOnline));
|
|
|
|
friend = FriendList[block.AgentID];
|
|
friend.IsOnline = false;
|
|
}
|
|
|
|
if (OnFriendOffline != null)
|
|
{
|
|
try { OnFriendOffline(friend); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Handle notifications sent when a friend rights change. This notification is also received
|
|
/// when my own rights change.
|
|
/// </summary>
|
|
/// <param name="packet"></param>
|
|
/// <param name="simulator"></param>
|
|
private void ChangeUserRightsHandler(Packet packet, Simulator simulator)
|
|
{
|
|
if (packet.Type == PacketType.ChangeUserRights)
|
|
{
|
|
FriendInfo friend;
|
|
ChangeUserRightsPacket rights = (ChangeUserRightsPacket)packet;
|
|
|
|
foreach (ChangeUserRightsPacket.RightsBlock block in rights.Rights)
|
|
{
|
|
FriendRights newRights = (FriendRights)block.RelatedRights;
|
|
if (FriendList.TryGetValue(block.AgentRelated, out friend))
|
|
{
|
|
friend.TheirFriendRights = newRights;
|
|
if (OnFriendRights != null)
|
|
{
|
|
try { OnFriendRights(friend); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
else if (block.AgentRelated == Client.Self.AgentID)
|
|
{
|
|
if (FriendList.TryGetValue(rights.AgentData.AgentID, out friend))
|
|
{
|
|
friend.MyFriendRights = newRights;
|
|
if (OnFriendRights != null)
|
|
{
|
|
try { OnFriendRights(friend); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle friend location updates
|
|
/// </summary>
|
|
/// <param name="packet">The Packet</param>
|
|
/// <param name="simulator">The Simulator</param>
|
|
public void OnFindAgentReplyHandler(Packet packet, Simulator simulator)
|
|
{
|
|
if(OnFriendFound != null)
|
|
{
|
|
FindAgentPacket reply = (FindAgentPacket)packet;
|
|
|
|
float x,y;
|
|
UUID prey = reply.AgentBlock.Prey;
|
|
ulong regionHandle = Helpers.GlobalPosToRegionHandle((float)reply.LocationBlock[0].GlobalX,
|
|
(float)reply.LocationBlock[0].GlobalY, out x, out y);
|
|
Vector3 xyz = new Vector3(x, y, 0f);
|
|
|
|
try { OnFriendFound(prey, regionHandle, xyz); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Handles relevant messages from the server encapsulated in instant messages.
|
|
/// </summary>
|
|
/// <param name="im">InstantMessage object containing encapsalated instant message</param>
|
|
/// <param name="simulator">Originating Simulator</param>
|
|
private void MainAvatar_InstantMessage(InstantMessage im, Simulator simulator)
|
|
{
|
|
if (im.Dialog == InstantMessageDialog.FriendshipOffered)
|
|
{
|
|
if (OnFriendshipOffered != null)
|
|
{
|
|
lock (FriendRequests)
|
|
{
|
|
if (FriendRequests.ContainsKey(im.FromAgentID))
|
|
FriendRequests[im.FromAgentID] = im.IMSessionID;
|
|
else
|
|
FriendRequests.Add(im.FromAgentID, im.IMSessionID);
|
|
}
|
|
try { OnFriendshipOffered(im.FromAgentID, im.FromAgentName, im.IMSessionID); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
else if (im.Dialog == InstantMessageDialog.FriendshipAccepted)
|
|
{
|
|
FriendInfo friend = new FriendInfo(im.FromAgentID, FriendRights.CanSeeOnline,
|
|
FriendRights.CanSeeOnline);
|
|
friend.Name = im.FromAgentName;
|
|
lock (FriendList) FriendList[friend.UUID] = friend;
|
|
|
|
if (OnFriendshipResponse != null)
|
|
{
|
|
try { OnFriendshipResponse(im.FromAgentID, im.FromAgentName, true); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
else if (im.Dialog == InstantMessageDialog.FriendshipDeclined)
|
|
{
|
|
if (OnFriendshipResponse != null)
|
|
{
|
|
try { OnFriendshipResponse(im.FromAgentID, im.FromAgentName, false); }
|
|
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason,
|
|
LoginResponseData replyData)
|
|
{
|
|
if (loginSuccess && replyData.BuddyList != null)
|
|
{
|
|
lock (FriendList)
|
|
{
|
|
for (int i = 0; i < replyData.BuddyList.Length; i++)
|
|
{
|
|
FriendInfo friend = replyData.BuddyList[i];
|
|
FriendList[friend.UUID] = friend;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|