using System; using System.Linq; using System.Collections.Generic; using ACE.Database.Models.Shard; using ACE.Server.Managers; namespace ACE.Server.Network.GameEvent.Events { public class GameEventFriendsListUpdate : GameEventMessage { [Flags] public enum FriendsUpdateTypeFlag { FullList = 0x0000, FriendAdded = 0x0001, FriendRemoved = 0x0002, FriendStatusChanged = 0x0004 } private readonly FriendsUpdateTypeFlag updateType; private readonly CharacterPropertiesFriendList friend; private readonly bool overrideOnlineStatus; private readonly bool onlineStatusVal; /// /// This constructor should only be used for sending the full friend list /// /// public GameEventFriendsListUpdate(Session session) : base(GameEventType.FriendsListUpdate, GameMessageGroup.UIQueue, session, 4096) // 2,062 is the average seen in retail pcaps, 36,916 is the max seen in retail pcaps { updateType = FriendsUpdateTypeFlag.FullList; WriteEventBody(); } /// /// This constructor is used for passing in a single friend for and add, remove, or update status. It also allows you to override the online status so the WorldManager isn't checked. /// /// /// /// /// Set to true if you want to force a value for the online status of the friend. Useful if you know the status and don't want to have the WorldManager check /// If overrideOnlineStatus is true, then this is the online status value that you want to force in the packet public GameEventFriendsListUpdate(Session session, FriendsUpdateTypeFlag updateType, CharacterPropertiesFriendList friend, bool overrideOnlineStatus = false, bool onlineStatusVal = false) : base(GameEventType.FriendsListUpdate, GameMessageGroup.UIQueue, session) { this.updateType = updateType; this.friend = friend; this.overrideOnlineStatus = overrideOnlineStatus; this.onlineStatusVal = onlineStatusVal; WriteEventBody(); } private void WriteEventBody() { List friendList; if (updateType == FriendsUpdateTypeFlag.FullList) friendList = Session.Player.Character.GetFriends(Session.Player.CharacterDatabaseLock); else friendList = new List() { friend }; Writer.Write((uint)friendList.Count); foreach (var f in friendList) { var player = PlayerManager.FindByGuid(f.FriendId, out var isOnline); var friendName = (player != null) ? player.Name : ""; if (overrideOnlineStatus) isOnline = onlineStatusVal; else if (isOnline) { // Does this friend want to appear offline? var onlineFriend = PlayerManager.GetOnlinePlayer(f.FriendId); if (onlineFriend != null && onlineFriend.GetAppearOffline()) isOnline = false; } Writer.Write(f.FriendId); // Friend's ID Writer.Write(isOnline ? 1u : 0u); // Whether this friend is online Writer.Write(0u); // Whether the friend should appear to be offline Writer.WriteString16L(friendName); // Name of the friend // send the list of friend's friends Writer.Write((uint)0/* TODO player.Character.CharacterPropertiesFriendList.Count*/); /*foreach (var friendFriend in player.Character.CharacterPropertiesFriendList) Writer.Write(friendFriend.FriendId);*/ // todo: send the inverse list of friend's friends Writer.Write((uint)0/* TODO playersFriend.Character.CharacterPropertiesFriendList.Count*/); /*foreach (var friendFriend in playersFriend.Character.CharacterPropertiesFriendList) Writer.Write(friendFriend.FriendId);*/ } Writer.Write((uint)updateType); } } }