internal async Task UpdateList(CMsgClientFriendsList list) { await _slim.WaitAsync(); var users = new List <(IUser Before, IUser After)>(); var clans = new List <(IClan Before, IClan After)>(); try { if (list.max_friend_countSpecified) { _maxFriendsCount = list.max_friend_count; } if (!list.bincremental) { _users.Clear(); _clans.Clear(); } foreach (var friend in list.friends) { SteamId friendId = friend.ulfriendid; if (friendId.IsIndividualAccount) { IUser before; IUser after; var relationship = (FriendRelationship)friend.efriendrelationship; if (_users.TryGetValue(friendId, out var user)) // if we have a user already { before = user; if (relationship == FriendRelationship.None) // and the new relationship is "None" { _users.Remove(friendId); // remove them and tell everyone they don't exist anymore after = null; } else // otherwise... { if (user is UnknownUser) // if they were previously unknown { after = new UnknownUser(user.Id, relationship); // make the after user just another unknown user } else { User realUser = (User)user; // otherwise after = realUser.WithRelationship(relationship); // clone the existing one and add a relationship } } } else // or unless we don't have that user { before = null; after = new UnknownUser(friendId, relationship); // make a new unknown one and tell everyone that person now exists _users[friendId] = after; } users.Add((before, after)); // tell everyone we're bffs or whatever } else if (friendId.IsClan) { IClan before; IClan after; var relationship = (ClanRelationship)friend.efriendrelationship; if (_clans.TryGetValue(friendId, out var clan)) { before = clan; if (relationship == ClanRelationship.None) { _users.Remove(friendId); after = null; } else { if (clan is UnknownClan) { after = new UnknownClan(clan.Id, relationship); } else { Clan realClan = (Clan)clan; after = realClan.WithRelationship(relationship); } } } else { before = null; after = new UnknownClan(friendId, relationship); _clans[friendId] = after; } clans.Add((before, after)); } } } finally { _slim.Release(); } // send update notifications outside the lock so other threads can update if possible await Task.WhenAll(users.Select(t => InvokeUserUpdated(t.Before, t.After)).Concat(clans.Select(t => InvokeClanUpdated(t.Before, t.After)))).ConfigureAwait(false); }
internal async Task UpdateFriend(CMsgClientPersonaState persona) { var users = new List <(IUser Before, IUser After)>(); var clans = new List <(IClan Before, IClan After)>(); ISelfUser currentBefore = null; ISelfUser currentAfter = null; await _slim.WaitAsync(); try { var flag = (ClientPersonaStateFlag)persona.status_flags; foreach (var friend in persona.friends) { SteamId friendId = friend.friendid; if (friendId == Client.SteamId) // that's us! { currentBefore = _currentUser; if (currentBefore is OfflineSelfUser) { currentAfter = SelfUser.Create(Client, friend, flag); } else { currentAfter = (currentBefore as SelfUser).WithState(friend, flag); } } else if (friendId.IsClan) { IClan before; IClan after; before = _clans[friend.friendid]; if (before is UnknownUser) { after = Clan.Create(Client, before.Relationship, friend, flag); } else { after = (before as Clan).WithPersonaState(friend, flag); } _clans[after.Id] = after; clans.Add((before, after)); } else { IUser before; IUser after; before = _users[friend.friendid]; if (before is UnknownUser) { after = User.Create(Client, before.Relationship, friend, flag); } else { after = (before as User).WithState(friend, flag); } _users[after.Id] = after; users.Add((before, after)); } } } finally { _slim.Release(); } if (currentBefore != null || currentAfter != null) { _currentUser = currentAfter; await InvokeCurrentUserUpdated(currentBefore, currentAfter).ConfigureAwait(false); } await Task.WhenAll(users.Select(t => InvokeUserUpdated(t.Before, t.After)).Concat(clans.Select(t => InvokeClanUpdated(t.Before, t.After)))).ConfigureAwait(false); }