-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathFriend.cs
More file actions
132 lines (121 loc) · 4.97 KB
/
Friend.cs
File metadata and controls
132 lines (121 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using Atlasd.Battlenet.Protocols.Game;
using System;
using System.Collections.Generic;
using System.Text;
namespace Atlasd.Battlenet
{
class Friend
{
public enum Location : byte
{
Offline = 0x00,
NotInChat = 0x01,
InChat = 0x02,
InPublicGame = 0x03,
InPrivateGame = 0x04,
InPasswordGame = 0x05,
};
[Flags]
public enum Status : byte
{
None = 0x00,
Mutual = 0x01,
DoNotDisturb = 0x02,
Away = 0x04,
};
public Location LocationId { get; private set; }
public byte[] LocationString { get; private set; }
public Status StatusId { get; private set; }
public Product.ProductCode ProductCode { get; private set; }
public byte[] Username { get; private set; }
/**
* <param name="source">The context GameState to sync from.</param>
* <param name="username">The online name of the user to befriend.</param>
*/
public Friend(GameState source, byte[] username)
{
Username = username;
Sync(source);
}
/**
* <remarks>Syncs the object properties with the context of the source GameState.</remarks>
* <param name="source">The context GameState to sync from.</param>
*/
public void Sync(GameState source)
{
LocationId = Location.Offline;
LocationString = new byte[0];
ProductCode = Product.ProductCode.None;
StatusId = Status.None;
if (source == null || source.ActiveAccount == null ||
!Common.GetClientByOnlineName(Encoding.UTF8.GetString(Username), out var target) ||
target == null || target.ActiveAccount == null)
{
return;
}
// Enforce consistent lock ordering to prevent ABBA deadlock.
// Always lock the object with the lower RuntimeHelpers hash first.
var first = source;
var second = target;
if (System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(source) >
System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(target))
{
first = target;
second = source;
}
lock (first)
{
lock (second)
{
var admin = source.HasAdmin();
var mutual = false;
var sourceFriendStrings = (List<byte[]>)source.ActiveAccount.Get(Account.FriendsKey, new List<byte[]>());
var targetFriendStrings = (List<byte[]>)target.ActiveAccount.Get(Account.FriendsKey, new List<byte[]>());
foreach (var targetFriendString in targetFriendStrings)
{
foreach (var sourceFriendString in sourceFriendStrings)
{
string aString = Encoding.UTF8.GetString(sourceFriendString);
string bString = Encoding.UTF8.GetString(targetFriendString);
if (string.Equals(aString, bString, StringComparison.CurrentCultureIgnoreCase))
{
mutual = true;
break;
}
}
if (mutual) break;
}
if (mutual) StatusId |= Status.Mutual;
if (!string.IsNullOrEmpty(target.Away)) StatusId |= Status.Away;
if (!string.IsNullOrEmpty(target.DoNotDisturb)) StatusId |= Status.DoNotDisturb;
if (target.ActiveChannel == null && target.GameAd == null)
{
LocationId = Location.NotInChat;
}
else if (target.ActiveChannel != null)
{
LocationId = Location.InChat;
if (mutual || admin) LocationString = Encoding.UTF8.GetBytes(target.ActiveChannel.Name);
}
else if (target.GameAd != null)
{
if (!target.GameAd.ActiveStateFlags.HasFlag(GameAd.StateFlags.Private) && target.GameAd.Password.Length == 0)
{
LocationId = Location.InPublicGame;
LocationString = target.GameAd.Name;
}
else if (!(mutual || admin))
{
LocationId = Location.InPrivateGame;
}
else
{
LocationId = Location.InPasswordGame;
LocationString = target.GameAd.Name;
}
}
}
}
}
}
}