@@ -235,6 +235,9 @@ | |||
<Compile Include="..\Discord.Net\Models\Channel.cs"> | |||
<Link>Models\Channel.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\Color.cs"> | |||
<Link>Models\Color.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\Invite.cs"> | |||
<Link>Models\Invite.cs</Link> | |||
</Compile> | |||
@@ -244,11 +247,8 @@ | |||
<Compile Include="..\Discord.Net\Models\Message.cs"> | |||
<Link>Models\Message.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\PackedColor.cs"> | |||
<Link>Models\PackedColor.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\PackedPermissions.cs"> | |||
<Link>Models\PackedPermissions.cs</Link> | |||
<Compile Include="..\Discord.Net\Models\Permissions.cs"> | |||
<Link>Models\Permissions.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\Role.cs"> | |||
<Link>Models\Role.cs</Link> | |||
@@ -8,29 +8,29 @@ namespace Discord | |||
{ | |||
public partial class DiscordClient | |||
{ | |||
public Task SetChannelUserPermissions(Channel channel, Member member, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelUserPermissions(Channel channel, Member member, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(channel, member?.UserId, PermissionTarget.Member, allow, deny); | |||
public Task SetChannelUserPermissions(string channelId, Member member, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelUserPermissions(string channelId, Member member, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(_channels[channelId], member?.UserId, PermissionTarget.Member, allow, deny); | |||
public Task SetChannelUserPermissions(Channel channel, User user, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelUserPermissions(Channel channel, User user, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(channel, user?.Id, PermissionTarget.Member, allow, deny); | |||
public Task SetChannelUserPermissions(string channelId, User user, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelUserPermissions(string channelId, User user, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(_channels[channelId], user?.Id, PermissionTarget.Member, allow, deny); | |||
public Task SetChannelUserPermissions(Channel channel, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelUserPermissions(Channel channel, string userId, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(channel, userId, PermissionTarget.Member, allow, deny); | |||
public Task SetChannelUserPermissions(string channelId, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelUserPermissions(string channelId, string userId, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(_channels[channelId], userId, PermissionTarget.Member, allow, deny); | |||
public Task SetChannelRolePermissions(Channel channel, Role role, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelRolePermissions(Channel channel, Role role, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(channel, role?.Id, PermissionTarget.Role, allow, deny); | |||
public Task SetChannelRolePermissions(string channelId, Role role, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelRolePermissions(string channelId, Role role, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(_channels[channelId], role?.Id, PermissionTarget.Role, allow, deny); | |||
public Task SetChannelRolePermissions(Channel channel, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelRolePermissions(Channel channel, string userId, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(channel, userId, PermissionTarget.Role, allow, deny); | |||
public Task SetChannelRolePermissions(string channelId, string userId, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
public Task SetChannelRolePermissions(string channelId, string userId, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
=> SetChannelPermissions(_channels[channelId], userId, PermissionTarget.Role, allow, deny); | |||
private async Task SetChannelPermissions(Channel channel, string targetId, string targetType, PackedChannelPermissions allow = null, PackedChannelPermissions deny = null) | |||
private async Task SetChannelPermissions(Channel channel, string targetId, string targetType, ChannelPermissions allow = null, ChannelPermissions deny = null) | |||
{ | |||
CheckReady(); | |||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | |||
@@ -91,9 +91,9 @@ namespace Discord | |||
return role; | |||
} | |||
public Task EditRole(string roleId, string name = null, PackedServerPermissions permissions = null, PackedColor color = null, bool? hoist = null, int? position = null) | |||
public Task EditRole(string roleId, string name = null, ServerPermissions permissions = null, Color color = null, bool? hoist = null, int? position = null) | |||
=> EditRole(_roles[roleId], name: name, permissions: permissions, color: color, hoist: hoist, position: position); | |||
public async Task EditRole(Role role, string name = null, PackedServerPermissions permissions = null, PackedColor color = null, bool? hoist = null, int? position = null) | |||
public async Task EditRole(Role role, string name = null, ServerPermissions permissions = null, Color color = null, bool? hoist = null, int? position = null) | |||
{ | |||
CheckReady(); | |||
if (role == null) throw new ArgumentNullException(nameof(role)); | |||
@@ -8,8 +8,17 @@ namespace Discord | |||
{ | |||
internal sealed class Servers : AsyncCollection<Server> | |||
{ | |||
private const string PMServerId = "Private"; | |||
Server PMServer { get; } | |||
public Servers(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) | |||
{ | |||
PMServer = new Server(client, PMServerId) { IsVirtual = true }; | |||
PMServer.Update(new API.ExtendedGuildInfo { Id = PMServerId, Name = PMServerId }); | |||
_dictionary[PMServerId] = PMServer; | |||
} | |||
public Server GetOrAdd(string id) | |||
=> GetOrAdd(id, () => new Server(_client, id)); | |||
@@ -57,10 +66,12 @@ namespace Discord | |||
} | |||
/// <summary> Returns a collection of all servers this client is a member of. </summary> | |||
public IEnumerable<Server> AllServers => _servers; | |||
public IEnumerable<Server> AllServers => _servers.Where(x => !x.IsVirtual); | |||
internal Servers Servers => _servers; | |||
private readonly Servers _servers; | |||
public Server PMServer { get; } | |||
/// <summary> Returns the server with the specified id, or null if none was found. </summary> | |||
public Server GetServer(string id) => _servers[id]; | |||
@@ -13,15 +13,15 @@ namespace Discord | |||
{ | |||
public string TargetType { get; } | |||
public string TargetId { get; } | |||
public PackedChannelPermissions Allow { get; } | |||
public PackedChannelPermissions Deny { get; } | |||
public ChannelPermissions Allow { get; } | |||
public ChannelPermissions Deny { get; } | |||
internal PermissionOverwrite(string type, string targetId, uint allow, uint deny) | |||
{ | |||
TargetType = type; | |||
TargetId = targetId; | |||
Allow = new PackedChannelPermissions(allow); | |||
Deny = new PackedChannelPermissions( deny); | |||
Allow = new ChannelPermissions(allow); | |||
Deny = new ChannelPermissions( deny); | |||
Allow.Lock(); | |||
Deny.Lock(); | |||
} | |||
@@ -0,0 +1,81 @@ | |||
using System; | |||
namespace Discord | |||
{ | |||
public class Color | |||
{ | |||
public static readonly Color Default = PresetColor(0); | |||
public static readonly Color Cyan = PresetColor(0x1abc9c); | |||
public static readonly Color DarkCyan = PresetColor(0x11806a); | |||
public static readonly Color Green = PresetColor(0x2ecc71); | |||
public static readonly Color DarkGreen = PresetColor(0x1f8b4c); | |||
public static readonly Color Blue = PresetColor(0x3498db); | |||
public static readonly Color DarkBlue = PresetColor(0x206694); | |||
public static readonly Color Purple = PresetColor(0x9b59b6); | |||
public static readonly Color DarkPurple = PresetColor(0x71368a); | |||
public static readonly Color Red = PresetColor(0xe74c3c); | |||
public static readonly Color DarkRed = PresetColor(0x992d22); | |||
public static readonly Color Orange = PresetColor(0xe67e22); | |||
public static readonly Color DarkOrange = PresetColor(0xa84300); | |||
public static readonly Color Navy = PresetColor(0x34495e); | |||
public static readonly Color DarkNavy = PresetColor(0x2c3e50); | |||
public static readonly Color Gold = PresetColor(0xf1c40f); | |||
public static readonly Color DarkGold = PresetColor(0xc27c0e); | |||
public static readonly Color LighterGrey = PresetColor(0xbcc0c0); | |||
public static readonly Color LightGrey = PresetColor(0x95a5a6); | |||
public static readonly Color DarkGrey = PresetColor(0x979c9f); | |||
public static readonly Color DarkerGrey = PresetColor(0x7f8c8d); | |||
private static Color PresetColor(uint packedValue) | |||
{ | |||
Color color = new Color(packedValue); | |||
color.Lock(); | |||
return color; | |||
} | |||
private bool _isLocked; | |||
private uint _rawValue; | |||
public uint RawValue | |||
{ | |||
get { return _rawValue; } | |||
set | |||
{ | |||
if (_isLocked) | |||
throw new InvalidOperationException("Unable to edit cached colors directly, use Copy() to make an editable copy."); | |||
_rawValue = value; | |||
} | |||
} | |||
public Color(uint rawValue) { _rawValue = rawValue; } | |||
public Color(byte r, byte g, byte b) : this(((uint)r << 16) | ((uint)g << 8) | b) { } | |||
public Color(float r, float g, float b) : this((byte)(r * 255.0f), (byte)(g * 255.0f), (byte)(b * 255.0f)) { } | |||
/// <summary> Gets or sets the red component for this color. </summary> | |||
public byte R { get { return GetByte(3); } set { SetByte(3, value); } } | |||
/// <summary> Gets or sets the green component for this color. </summary> | |||
public byte G { get { return GetByte(2); } set { SetByte(2, value); } } | |||
/// <summary> Gets or sets the blue component for this color. </summary> | |||
public byte B { get { return GetByte(1); } set { SetByte(1, value); } } | |||
internal void Lock() => _isLocked = true; | |||
internal void SetRawValue(uint rawValue) | |||
{ | |||
//Bypasses isLocked for API changes. | |||
_rawValue = rawValue; | |||
} | |||
protected byte GetByte(int pos) => (byte)((_rawValue >> (8 * (pos - 1))) & 0xFF); | |||
protected void SetByte(int pos, byte value) | |||
{ | |||
if (_isLocked) | |||
throw new InvalidOperationException("Unable to edit cached colors directly, use Copy() to make an editable copy."); | |||
uint original = _rawValue; | |||
int bit = 8 * (pos - 1); | |||
uint mask = (uint)~(0xFF << bit); | |||
_rawValue = (_rawValue & mask) | ((uint)value << bit); | |||
} | |||
} | |||
} |
@@ -10,7 +10,7 @@ namespace Discord | |||
public class Member | |||
{ | |||
private readonly DiscordClient _client; | |||
private ConcurrentDictionary<string, PackedChannelPermissions> _permissions; | |||
private ConcurrentDictionary<string, ChannelPermissions> _permissions; | |||
private bool _hasRef; | |||
/// <summary> Returns the name of this user on this server. </summary> | |||
@@ -76,7 +76,7 @@ namespace Discord | |||
ServerId = serverId; | |||
Status = UserStatus.Offline; | |||
RoleIds = _initialRoleIds; | |||
_permissions = new ConcurrentDictionary<string, PackedChannelPermissions>(); | |||
_permissions = new ConcurrentDictionary<string, ChannelPermissions>(); | |||
} | |||
internal void OnCached() | |||
{ | |||
@@ -210,13 +210,13 @@ namespace Discord | |||
if (server == null) return; | |||
var channel = _client.Channels[channelId]; | |||
PackedChannelPermissions permissions; | |||
ChannelPermissions permissions; | |||
if (!_permissions.TryGetValue(channelId, out permissions)) return; | |||
uint newPermissions = 0x0; | |||
uint oldPermissions = permissions.RawValue; | |||
if (UserId == server.OwnerId) | |||
newPermissions = PackedChannelPermissions.All.RawValue; | |||
newPermissions = ChannelPermissions.All.RawValue; | |||
else | |||
{ | |||
if (channel == null) return; | |||
@@ -239,7 +239,7 @@ namespace Discord | |||
permissions.SetRawValueInternal(newPermissions); | |||
if (permissions.General_ManagePermissions) | |||
permissions.SetRawValueInternal(PackedChannelPermissions.All.RawValue); | |||
permissions.SetRawValueInternal(ChannelPermissions.All.RawValue); | |||
/*else if (server.DefaultChannelId == channelId) | |||
permissions.SetBitInternal(PackedPermissions.Text_ReadMessagesBit, true);*/ | |||
@@ -247,13 +247,13 @@ namespace Discord | |||
channel.InvalidMembersCache(); | |||
} | |||
//TODO: Add GetServerPermissions | |||
public PackedChannelPermissions GetPermissions(Channel channel) | |||
public ChannelPermissions GetPermissions(Channel channel) | |||
=> GetPermissions(channel?.Id); | |||
public PackedChannelPermissions GetPermissions(string channelId) | |||
public ChannelPermissions GetPermissions(string channelId) | |||
{ | |||
if (channelId == null) throw new ArgumentNullException(nameof(channelId)); | |||
PackedChannelPermissions perms; | |||
ChannelPermissions perms; | |||
if (_permissions.TryGetValue(channelId, out perms)) | |||
return perms; | |||
return null; | |||
@@ -261,14 +261,14 @@ namespace Discord | |||
internal void AddChannel(string channelId) | |||
{ | |||
var perms = new PackedChannelPermissions(); | |||
var perms = new ChannelPermissions(); | |||
perms.Lock(); | |||
_permissions.TryAdd(channelId, perms); | |||
UpdatePermissions(channelId); | |||
} | |||
internal bool RemoveChannel(string channelId) | |||
{ | |||
PackedChannelPermissions ignored; | |||
ChannelPermissions ignored; | |||
return _permissions.TryRemove(channelId, out ignored); | |||
} | |||
@@ -1,81 +0,0 @@ | |||
using System; | |||
namespace Discord | |||
{ | |||
public class PackedColor | |||
{ | |||
public static readonly PackedColor Default = PresetColor(0); | |||
public static readonly PackedColor Cyan = PresetColor(0x1abc9c); | |||
public static readonly PackedColor DarkCyan = PresetColor(0x11806a); | |||
public static readonly PackedColor Green = PresetColor(0x2ecc71); | |||
public static readonly PackedColor DarkGreen = PresetColor(0x1f8b4c); | |||
public static readonly PackedColor Blue = PresetColor(0x3498db); | |||
public static readonly PackedColor DarkBlue = PresetColor(0x206694); | |||
public static readonly PackedColor Purple = PresetColor(0x9b59b6); | |||
public static readonly PackedColor DarkPurple = PresetColor(0x71368a); | |||
public static readonly PackedColor Red = PresetColor(0xe74c3c); | |||
public static readonly PackedColor DarkRed = PresetColor(0x992d22); | |||
public static readonly PackedColor Orange = PresetColor(0xe67e22); | |||
public static readonly PackedColor DarkOrange = PresetColor(0xa84300); | |||
public static readonly PackedColor Navy = PresetColor(0x34495e); | |||
public static readonly PackedColor DarkNavy = PresetColor(0x2c3e50); | |||
public static readonly PackedColor Gold = PresetColor(0xf1c40f); | |||
public static readonly PackedColor DarkGold = PresetColor(0xc27c0e); | |||
public static readonly PackedColor LighterGrey = PresetColor(0xbcc0c0); | |||
public static readonly PackedColor LightGrey = PresetColor(0x95a5a6); | |||
public static readonly PackedColor DarkGrey = PresetColor(0x979c9f); | |||
public static readonly PackedColor DarkerGrey = PresetColor(0x7f8c8d); | |||
private static PackedColor PresetColor(uint packedValue) | |||
{ | |||
PackedColor color = new PackedColor(packedValue); | |||
color.Lock(); | |||
return color; | |||
} | |||
private bool _isLocked; | |||
private uint _rawValue; | |||
public uint RawValue | |||
{ | |||
get { return _rawValue; } | |||
set | |||
{ | |||
if (_isLocked) | |||
throw new InvalidOperationException("Unable to edit cached colors directly, use Copy() to make an editable copy."); | |||
_rawValue = value; | |||
} | |||
} | |||
public PackedColor(uint rawValue) { _rawValue = rawValue; } | |||
public PackedColor(byte r, byte g, byte b) : this(((uint)r << 16) | ((uint)g << 8) | b) { } | |||
public PackedColor(float r, float g, float b) : this((byte)(r * 255.0f), (byte)(g * 255.0f), (byte)(b * 255.0f)) { } | |||
/// <summary> Gets or sets the red component for this color. </summary> | |||
public byte R { get { return GetByte(3); } set { SetByte(3, value); } } | |||
/// <summary> Gets or sets the green component for this color. </summary> | |||
public byte G { get { return GetByte(2); } set { SetByte(2, value); } } | |||
/// <summary> Gets or sets the blue component for this color. </summary> | |||
public byte B { get { return GetByte(1); } set { SetByte(1, value); } } | |||
internal void Lock() => _isLocked = true; | |||
internal void SetRawValue(uint rawValue) | |||
{ | |||
//Bypasses isLocked for API changes. | |||
_rawValue = rawValue; | |||
} | |||
protected byte GetByte(int pos) => (byte)((_rawValue >> (8 * (pos - 1))) & 0xFF); | |||
protected void SetByte(int pos, byte value) | |||
{ | |||
if (_isLocked) | |||
throw new InvalidOperationException("Unable to edit cached colors directly, use Copy() to make an editable copy."); | |||
uint original = _rawValue; | |||
int bit = 8 * (pos - 1); | |||
uint mask = (uint)~(0xFF << bit); | |||
_rawValue = (_rawValue & mask) | ((uint)value << bit); | |||
} | |||
} | |||
} |
@@ -2,19 +2,19 @@ | |||
namespace Discord | |||
{ | |||
public sealed class PackedServerPermissions : PackedPermissions | |||
public sealed class ServerPermissions : Permissions | |||
{ | |||
public static PackedServerPermissions None { get; } | |||
public static PackedServerPermissions All { get; } | |||
static PackedServerPermissions() | |||
public static ServerPermissions None { get; } | |||
public static ServerPermissions All { get; } | |||
static ServerPermissions() | |||
{ | |||
None = new PackedServerPermissions(); | |||
None = new ServerPermissions(); | |||
None.Lock(); | |||
All = new PackedServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); | |||
All = new ServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); | |||
All.Lock(); | |||
} | |||
public PackedServerPermissions(uint rawValue = 0) : base(rawValue) { } | |||
public ServerPermissions(uint rawValue = 0) : base(rawValue) { } | |||
/// <summary> If True, a user may ban users from the server. </summary> | |||
public bool General_BanMembers { get { return GetBit(General_BanMembersBit); } set { SetBit(General_BanMembersBit, value); } } | |||
@@ -27,32 +27,32 @@ namespace Discord | |||
/// <summary> If True, a user may adjust server properties. </summary> | |||
public bool General_ManageServer { get { return GetBit(General_ManageServerBit); } set { SetBit(General_ManageServerBit, value); } } | |||
public PackedServerPermissions Copy() => new PackedServerPermissions(RawValue); | |||
public ServerPermissions Copy() => new ServerPermissions(RawValue); | |||
} | |||
public sealed class PackedChannelPermissions : PackedPermissions | |||
public sealed class ChannelPermissions : Permissions | |||
{ | |||
public static PackedChannelPermissions None { get; } | |||
public static PackedChannelPermissions All { get; } | |||
static PackedChannelPermissions() | |||
public static ChannelPermissions None { get; } | |||
public static ChannelPermissions All { get; } | |||
static ChannelPermissions() | |||
{ | |||
None = new PackedChannelPermissions(); | |||
None = new ChannelPermissions(); | |||
None.Lock(); | |||
All = new PackedChannelPermissions(Convert.ToUInt32("00000011111100111111110000011001", 2)); | |||
All = new ChannelPermissions(Convert.ToUInt32("00000011111100111111110000011001", 2)); | |||
All.Lock(); | |||
} | |||
public PackedChannelPermissions(uint rawValue = 0) : base(rawValue) { } | |||
public ChannelPermissions(uint rawValue = 0) : base(rawValue) { } | |||
/// <summary> If True, a user may adjust permissions. This also implictly grants all other permissions. </summary> | |||
public bool General_ManagePermissions { get { return GetBit(General_ManagePermissionsBit); } set { SetBit(General_ManagePermissionsBit, value); } } | |||
/// <summary> If True, a user may create, delete and modify this channel. </summary> | |||
public bool General_ManageChannel { get { return GetBit(General_ManageChannelBit); } set { SetBit(General_ManageChannelBit, value); } } | |||
public PackedChannelPermissions Copy() => new PackedChannelPermissions(RawValue); | |||
public ChannelPermissions Copy() => new ChannelPermissions(RawValue); | |||
} | |||
public abstract class PackedPermissions | |||
public abstract class Permissions | |||
{ | |||
internal const byte General_CreateInstantInviteBit = 0; | |||
internal const byte General_BanMembersBit = 1; | |||
@@ -88,7 +88,7 @@ namespace Discord | |||
} | |||
} | |||
protected PackedPermissions(uint rawValue) { _rawValue = rawValue; } | |||
protected Permissions(uint rawValue) { _rawValue = rawValue; } | |||
/// <summary> If True, a user may create invites. </summary> | |||
public bool General_CreateInstantInvite { get { return GetBit(General_CreateInstantInviteBit); } set { SetBit(General_CreateInstantInviteBit, value); } } |
@@ -18,12 +18,12 @@ namespace Discord | |||
/// <summary> Returns the position of this channel in the role list for this server. </summary> | |||
public int Position { get; private set; } | |||
/// <summary> Returns the color of this role. </summary> | |||
public PackedColor Color { get; private set; } | |||
public Color Color { get; private set; } | |||
/// <summary> Returns whether this role is managed by server (e.g. for Twitch integration) </summary> | |||
public bool IsManaged { get; private set; } | |||
/// <summary> Returns the the permissions contained by this role. </summary> | |||
public PackedServerPermissions Permissions { get; } | |||
public ServerPermissions Permissions { get; } | |||
/// <summary> Returns the id of the server this role is a member of. </summary> | |||
public string ServerId { get; } | |||
@@ -45,9 +45,9 @@ namespace Discord | |||
_client = client; | |||
Id = id; | |||
ServerId = serverId; | |||
Permissions = new PackedServerPermissions(0); | |||
Permissions = new ServerPermissions(0); | |||
Permissions.Lock(); | |||
Color = new PackedColor(0); | |||
Color = new Color(0); | |||
Color.Lock(); | |||
if (IsEveryone) | |||
@@ -18,6 +18,8 @@ namespace Discord | |||
public string Name { get; private set; } | |||
/// <summary> Returns the current logged-in user's data for this server. </summary> | |||
public Member CurrentMember { get; internal set; } | |||
/// <summary> Returns true if this is a virtual server used by Discord.Net and not a real Discord server. </summary> | |||
public bool IsVirtual { get; internal set; } | |||
/// <summary> Returns the amount of time (in seconds) a user must be inactive for until they are automatically moved to the AFK channel (see AFKChannel). </summary> | |||
public int AFKTimeout { get; private set; } | |||