diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 387ceda6a..5a1d48082 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -16,18 +16,23 @@ jobs:
pool:
vmImage: 'ubuntu-16.04'
steps:
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core sdk'
+ inputs:
+ packageType: 'sdk'
+ version: '3.x'
- template: azure/build.yml
- job: Windows_build
pool:
- vmImage: 'vs2017-win2016'
+ vmImage: 'windows-2019'
condition: ne(variables['Build.SourceBranch'], 'refs/heads/dev')
steps:
- template: azure/build.yml
- job: Windows_deploy
pool:
- vmImage: 'vs2017-win2016'
+ vmImage: 'windows-2019'
condition: |
and (
succeeded(),
diff --git a/azure/deploy.yml b/azure/deploy.yml
index f2affe667..61994299e 100644
--- a/azure/deploy.yml
+++ b/azure/deploy.yml
@@ -1,32 +1,35 @@
steps:
- script: |
- dotnet pack "src\Discord.Net.Core\Discord.Net.Core.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
- dotnet pack "src\Discord.Net.Rest\Discord.Net.Rest.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
- dotnet pack "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
- dotnet pack "src\Discord.Net.Commands\Discord.Net.Commands.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
- dotnet pack "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
- dotnet pack "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
- dotnet pack "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "../../artifacts/" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.Core\Discord.Net.Core.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.Rest\Discord.Net.Rest.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.Commands\Discord.Net.Commands.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.Providers.WS4Net\Discord.Net.Providers.WS4Net.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
+ dotnet pack "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) -o "$(Build.ArtifactStagingDirectory)" /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag)
displayName: Pack projects
-- task: NuGet@0
- inputs:
- command: pack
- arguments: src/Discord.Net/Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix=""
+- task: NuGetCommand@2
displayName: Pack metapackage (release mode)
condition: eq(variables['buildTag'], True)
-
-- task: NuGet@0
inputs:
- command: pack
- arguments: src/Discord.Net/Discord.Net.nuspec -OutputDirectory "artifacts" -properties suffix="-$(buildNumber)"
+ command: 'pack'
+ packagesToPack: 'src/Discord.Net/Discord.Net.nuspec'
+ versioningScheme: 'off'
+
+- task: NuGetCommand@2
displayName: Pack metapackage
condition: eq(variables['buildTag'], False)
+ inputs:
+ command: 'pack'
+ packagesToPack: 'src/Discord.Net/Discord.Net.nuspec'
+ versioningScheme: 'off'
+ buildProperties: 'suffix=-$(buildNumber)'
- task: NuGetCommand@2
displayName: Push to NuGet
inputs:
command: push
nuGetFeedType: external
- packagesToPush: 'artifacts/*.nupkg'
+ packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg'
publishFeedCredentials: myget-discord
diff --git a/azure/docs.bat b/azure/docs.bat
index 572534cee..504e12991 100644
--- a/azure/docs.bat
+++ b/azure/docs.bat
@@ -5,7 +5,8 @@ ECHO remove old 'latest'
ECHO Y | RMDIR /S docs-static\latest || EXIT /B 1
ECHO build docs
-docfx.console\tools\docfx.exe docs/docfx.json -o docs-static/latest/ || EXIT /B 1
+docfx.console\tools\docfx.exe docs/docfx.json -o docs-staging || EXIT /B 1
+ROBOCOPY docs-staging\_site docs-static\latest /MIR
ECHO commit and deploy
git config --global user.name "Discord.Net CI Robot" && git config --global user.email "robot@foxbot.me"
diff --git a/docs/guides/commands/intro.md b/docs/guides/commands/intro.md
index c815175bd..f8ff1b596 100644
--- a/docs/guides/commands/intro.md
+++ b/docs/guides/commands/intro.md
@@ -111,7 +111,7 @@ optional, give it a default value (i.e., `int num = 0`).
#### Parameters with Spaces
-To accept a comma-separated list, set the parameter to `params Type[]`.
+To accept a space-separated list, set the parameter to `params Type[]`.
Should a parameter include spaces, the parameter **must** be
wrapped in quotes. For example, for a command with a parameter
@@ -218,4 +218,4 @@ Submodules are "modules" that reside within another one. Typically,
submodules are used to create nested groups (although not required to
create nested groups).
-[!code-csharp[Groups and Submodules](samples/intro/groups.cs)]
\ No newline at end of file
+[!code-csharp[Groups and Submodules](samples/intro/groups.cs)]
diff --git a/samples/01_basic_ping_bot/01_basic_ping_bot.csproj b/samples/01_basic_ping_bot/01_basic_ping_bot.csproj
index 5484e3d55..4b4e35e3f 100644
--- a/samples/01_basic_ping_bot/01_basic_ping_bot.csproj
+++ b/samples/01_basic_ping_bot/01_basic_ping_bot.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.0
diff --git a/samples/02_commands_framework/02_commands_framework.csproj b/samples/02_commands_framework/02_commands_framework.csproj
index f479ee0b0..84b30aa99 100644
--- a/samples/02_commands_framework/02_commands_framework.csproj
+++ b/samples/02_commands_framework/02_commands_framework.csproj
@@ -2,11 +2,11 @@
Exe
- netcoreapp2.0
+ netcoreapp3.0
-
+
diff --git a/samples/03_sharded_client/03_sharded_client.csproj b/samples/03_sharded_client/03_sharded_client.csproj
index 5d76961cd..a6599c117 100644
--- a/samples/03_sharded_client/03_sharded_client.csproj
+++ b/samples/03_sharded_client/03_sharded_client.csproj
@@ -2,10 +2,14 @@
Exe
- netcoreapp2.1
+ netcoreapp3.0
_03_sharded_client
+
+
+
+
diff --git a/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj b/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj
index 5da3d506d..1b2ee45bf 100644
--- a/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj
+++ b/src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj
@@ -1,13 +1,13 @@
-
+
Discord.Net.Analyzers
Discord.Analyzers
A Discord.Net extension adding support for design-time analysis of the API usage.
- netstandard1.3
+ netstandard2.0;netstandard2.1
-
+
diff --git a/src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs b/src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs
index 0760d019f..38d3f39d4 100644
--- a/src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs
+++ b/src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
@@ -24,6 +24,8 @@ namespace Discord.Analyzers
public override void Initialize(AnalysisContext context)
{
+ context.EnableConcurrentExecution();
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.RegisterSyntaxNodeAction(AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression);
}
diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs
index 3a7da3862..d5c060fe4 100644
--- a/src/Discord.Net.Commands/CommandService.cs
+++ b/src/Discord.Net.Commands/CommandService.cs
@@ -49,7 +49,7 @@ namespace Discord.Commands
private readonly ConcurrentDictionary _typedModuleDefs;
private readonly ConcurrentDictionary> _typeReaders;
private readonly ConcurrentDictionary _defaultTypeReaders;
- private readonly ImmutableList> _entityTypeReaders; //TODO: Candidate for C#7 Tuple
+ private readonly ImmutableList<(Type EntityType, Type TypeReaderType)> _entityTypeReaders;
private readonly HashSet _moduleDefs;
private readonly CommandMap _map;
@@ -124,11 +124,11 @@ namespace Discord.Commands
_defaultTypeReaders[typeof(string)] =
new PrimitiveTypeReader((string x, out string y) => { y = x; return true; }, 0);
- var entityTypeReaders = ImmutableList.CreateBuilder>();
- entityTypeReaders.Add(new Tuple(typeof(IMessage), typeof(MessageTypeReader<>)));
- entityTypeReaders.Add(new Tuple(typeof(IChannel), typeof(ChannelTypeReader<>)));
- entityTypeReaders.Add(new Tuple(typeof(IRole), typeof(RoleTypeReader<>)));
- entityTypeReaders.Add(new Tuple(typeof(IUser), typeof(UserTypeReader<>)));
+ var entityTypeReaders = ImmutableList.CreateBuilder<(Type, Type)>();
+ entityTypeReaders.Add((typeof(IMessage), typeof(MessageTypeReader<>)));
+ entityTypeReaders.Add((typeof(IChannel), typeof(ChannelTypeReader<>)));
+ entityTypeReaders.Add((typeof(IRole), typeof(RoleTypeReader<>)));
+ entityTypeReaders.Add((typeof(IUser), typeof(UserTypeReader<>)));
_entityTypeReaders = entityTypeReaders.ToImmutable();
}
@@ -408,7 +408,7 @@ namespace Discord.Commands
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsEnum)
return true;
- return _entityTypeReaders.Any(x => type == x.Item1 || typeInfo.ImplementedInterfaces.Contains(x.Item2));
+ return _entityTypeReaders.Any(x => type == x.EntityType || typeInfo.ImplementedInterfaces.Contains(x.TypeReaderType));
}
internal void AddNullableTypeReader(Type valueType, TypeReader valueTypeReader)
{
@@ -439,9 +439,9 @@ namespace Discord.Commands
//Is this an entity?
for (int i = 0; i < _entityTypeReaders.Count; i++)
{
- if (type == _entityTypeReaders[i].Item1 || typeInfo.ImplementedInterfaces.Contains(_entityTypeReaders[i].Item1))
+ if (type == _entityTypeReaders[i].EntityType || typeInfo.ImplementedInterfaces.Contains(_entityTypeReaders[i].EntityType))
{
- reader = Activator.CreateInstance(_entityTypeReaders[i].Item2.MakeGenericType(type)) as TypeReader;
+ reader = Activator.CreateInstance(_entityTypeReaders[i].TypeReaderType.MakeGenericType(type)) as TypeReader;
_defaultTypeReaders[type] = reader;
return reader;
}
diff --git a/src/Discord.Net.Commands/Discord.Net.Commands.csproj b/src/Discord.Net.Commands/Discord.Net.Commands.csproj
index 1bef1bfea..95e7db491 100644
--- a/src/Discord.Net.Commands/Discord.Net.Commands.csproj
+++ b/src/Discord.Net.Commands/Discord.Net.Commands.csproj
@@ -4,16 +4,11 @@
Discord.Net.Commands
Discord.Commands
A Discord.Net extension adding support for bot commands.
- net46;netstandard1.3;netstandard2.0
- netstandard1.3;netstandard2.0
+ net461;netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1
-
-
-
-
-
-
+
diff --git a/src/Discord.Net.Commands/Readers/UserTypeReader.cs b/src/Discord.Net.Commands/Readers/UserTypeReader.cs
index 6d9f1dd8c..c0104e341 100644
--- a/src/Discord.Net.Commands/Readers/UserTypeReader.cs
+++ b/src/Discord.Net.Commands/Readers/UserTypeReader.cs
@@ -49,7 +49,7 @@ namespace Discord.Commands
string username = input.Substring(0, index);
if (ushort.TryParse(input.Substring(index + 1), out ushort discriminator))
{
- var channelUser = await channelUsers.FirstOrDefault(x => x.DiscriminatorValue == discriminator &&
+ var channelUser = await channelUsers.FirstOrDefaultAsync(x => x.DiscriminatorValue == discriminator &&
string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)).ConfigureAwait(false);
AddResult(results, channelUser as T, channelUser?.Username == username ? 0.85f : 0.75f);
diff --git a/src/Discord.Net.Core/Discord.Net.Core.csproj b/src/Discord.Net.Core/Discord.Net.Core.csproj
index 20e57d346..dd2f2afe3 100644
--- a/src/Discord.Net.Core/Discord.Net.Core.csproj
+++ b/src/Discord.Net.Core/Discord.Net.Core.csproj
@@ -4,13 +4,13 @@
Discord.Net.Core
Discord
The core components for the Discord.Net library.
- net46;netstandard1.3;netstandard2.0
- netstandard1.3;netstandard2.0
+ net461;netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1
-
+
-
+
all
diff --git a/src/Discord.Net.Core/Entities/Activities/ActivityType.cs b/src/Discord.Net.Core/Entities/Activities/ActivityType.cs
index b603e27a4..8c44f49e3 100644
--- a/src/Discord.Net.Core/Entities/Activities/ActivityType.cs
+++ b/src/Discord.Net.Core/Entities/Activities/ActivityType.cs
@@ -20,6 +20,10 @@ namespace Discord
///
/// The user is watching some form of media.
///
- Watching = 3
+ Watching = 3,
+ ///
+ /// The user has set a custom status.
+ ///
+ CustomStatus = 4,
}
}
diff --git a/src/Discord.Net.Core/Entities/Activities/CustomStatusGame.cs b/src/Discord.Net.Core/Entities/Activities/CustomStatusGame.cs
new file mode 100644
index 000000000..7bd2664a2
--- /dev/null
+++ b/src/Discord.Net.Core/Entities/Activities/CustomStatusGame.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Diagnostics;
+
+namespace Discord
+{
+ ///
+ /// A user's activity for their custom status.
+ ///
+ [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
+ public class CustomStatusGame : Game
+ {
+ internal CustomStatusGame() { }
+
+ ///
+ /// Gets the emote, if it is set.
+ ///
+ ///
+ /// An containing the or set by the user.
+ ///
+ public IEmote Emote { get; internal set; }
+
+ ///
+ /// Gets the timestamp of when this status was created.
+ ///
+ ///
+ /// A containing the time when this status was created.
+ ///
+ public DateTimeOffset CreatedAt { get; internal set; }
+
+ ///
+ /// Gets the state of the status.
+ ///
+ public string State { get; internal set; }
+
+ public override string ToString()
+ => $"{Emote} {State}";
+
+ private string DebuggerDisplay => $"{Name}";
+ }
+}
diff --git a/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs b/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs
index e13536a97..ec31019af 100644
--- a/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs
+++ b/src/Discord.Net.Core/Entities/Guilds/GuildProperties.cs
@@ -1,3 +1,5 @@
+using System.Globalization;
+
namespace Discord
{
///
@@ -84,5 +86,23 @@ namespace Discord
/// are enabled, without the need to manipulate the logic of the flag.
///
public Optional SystemChannelFlags { get; set; }
+ ///
+ /// Gets or sets the preferred locale of the guild in IETF BCP 47 language tag format.
+ ///
+ ///
+ /// This property takes precedence over .
+ /// When it is set, the value of
+ /// will not be used.
+ ///
+ public Optional PreferredLocale { get; set; }
+ ///
+ /// Gets or sets the preferred locale of the guild.
+ ///
+ ///
+ /// The property takes precedence
+ /// over this property. When is set,
+ /// the value of will be unused.
+ ///
+ public Optional PreferredCulture { get; set; }
}
}
diff --git a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
index d463d86df..213091ad4 100644
--- a/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
+++ b/src/Discord.Net.Core/Entities/Guilds/IGuild.cs
@@ -1,6 +1,7 @@
using Discord.Audio;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Threading.Tasks;
namespace Discord
@@ -249,6 +250,24 @@ namespace Discord
///
int PremiumSubscriptionCount { get; }
+ ///
+ /// Gets the preferred locale of this guild in IETF BCP 47
+ /// language tag format.
+ ///
+ ///
+ /// The preferred locale of the guild in IETF BCP 47
+ /// language tag format.
+ ///
+ string PreferredLocale { get; }
+
+ ///
+ /// Gets the preferred culture of this guild.
+ ///
+ ///
+ /// The preferred culture information of this guild.
+ ///
+ CultureInfo PreferredCulture { get; }
+
///
/// Modifies this guild.
///
diff --git a/src/Discord.Net.Core/Entities/Messages/IMessage.cs b/src/Discord.Net.Core/Entities/Messages/IMessage.cs
index 1eba1e076..05f505269 100644
--- a/src/Discord.Net.Core/Entities/Messages/IMessage.cs
+++ b/src/Discord.Net.Core/Entities/Messages/IMessage.cs
@@ -140,6 +140,18 @@ namespace Discord
///
MessageApplication Application { get; }
+ ///
+ /// Gets the reference to the original message if it was crossposted.
+ ///
+ ///
+ /// Sent with Cross-posted messages, meaning they were published from news channels
+ /// and received by subscriber channels.
+ ///
+ ///
+ /// A message's reference, if any is associated.
+ ///
+ MessageReference Reference { get; }
+
///
/// Gets all reactions included in this message.
///
diff --git a/src/Discord.Net.Core/Entities/Messages/MessageReference.cs b/src/Discord.Net.Core/Entities/Messages/MessageReference.cs
new file mode 100644
index 000000000..57a508a7c
--- /dev/null
+++ b/src/Discord.Net.Core/Entities/Messages/MessageReference.cs
@@ -0,0 +1,33 @@
+using System.Diagnostics;
+
+namespace Discord
+{
+ ///
+ /// Contains the IDs sent from a crossposted message.
+ ///
+ [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
+ public class MessageReference
+ {
+ ///
+ /// Gets the Message ID of the original message.
+ ///
+ public Optional MessageId { get; internal set; }
+
+ ///
+ /// Gets the Channel ID of the original message.
+ ///
+ public ulong ChannelId { get; internal set; }
+
+ ///
+ /// Gets the Guild ID of the original message.
+ ///
+ public Optional GuildId { get; internal set; }
+
+ private string DebuggerDisplay
+ => $"Channel ID: ({ChannelId}){(GuildId.IsSpecified ? $", Guild ID: ({GuildId.Value})" : "")}" +
+ $"{(MessageId.IsSpecified ? $", Message ID: ({MessageId.Value})" : "")}";
+
+ public override string ToString()
+ => DebuggerDisplay;
+ }
+}
diff --git a/src/Discord.Net.Core/Entities/Roles/Color.cs b/src/Discord.Net.Core/Entities/Roles/Color.cs
index 6bfead3d6..b522ae47e 100644
--- a/src/Discord.Net.Core/Entities/Roles/Color.cs
+++ b/src/Discord.Net.Core/Entities/Roles/Color.cs
@@ -1,8 +1,6 @@
using System;
using System.Diagnostics;
-#if NETSTANDARD2_0 || NET45
using StandardColor = System.Drawing.Color;
-#endif
namespace Discord
{
@@ -190,12 +188,10 @@ namespace Discord
public override int GetHashCode() => RawValue.GetHashCode();
-#if NETSTANDARD2_0 || NET45
public static implicit operator StandardColor(Color color) =>
StandardColor.FromArgb((int)color.RawValue);
public static explicit operator Color(StandardColor color) =>
new Color((uint)color.ToArgb() << 8 >> 8);
-#endif
///
/// Gets the hexadecimal representation of the color (e.g. #000ccc).
diff --git a/src/Discord.Net.Core/Extensions/AsyncEnumerableExtensions.cs b/src/Discord.Net.Core/Extensions/AsyncEnumerableExtensions.cs
index 282d20517..d96076259 100644
--- a/src/Discord.Net.Core/Extensions/AsyncEnumerableExtensions.cs
+++ b/src/Discord.Net.Core/Extensions/AsyncEnumerableExtensions.cs
@@ -15,7 +15,7 @@ namespace Discord
/// Flattens the specified pages into one asynchronously.
public static async Task> FlattenAsync(this IAsyncEnumerable> source)
{
- return await source.Flatten().ToArray().ConfigureAwait(false);
+ return await source.Flatten().ToArrayAsync().ConfigureAwait(false);
}
/// Flattens the specified pages into one .
public static IAsyncEnumerable Flatten(this IAsyncEnumerable> source)
diff --git a/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs b/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs
index a31721875..84209902a 100644
--- a/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs
+++ b/src/Discord.Net.Core/Utils/Paging/PagedEnumerator.cs
@@ -25,26 +25,28 @@ namespace Discord
_nextPage = nextPage;
}
- public IAsyncEnumerator> GetEnumerator() => new Enumerator(this);
+ public IAsyncEnumerator> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) => new Enumerator(this, cancellationToken);
internal class Enumerator : IAsyncEnumerator>
{
private readonly PagedAsyncEnumerable _source;
+ private readonly CancellationToken _token;
private readonly PageInfo _info;
public IReadOnlyCollection Current { get; private set; }
- public Enumerator(PagedAsyncEnumerable source)
+ public Enumerator(PagedAsyncEnumerable source, CancellationToken token)
{
_source = source;
+ _token = token;
_info = new PageInfo(source._start, source._count, source.PageSize);
}
- public async Task MoveNext(CancellationToken cancelToken)
+ public async ValueTask MoveNextAsync()
{
if (_info.Remaining == 0)
return false;
- var data = await _source._getPage(_info, cancelToken).ConfigureAwait(false);
+ var data = await _source._getPage(_info, _token).ConfigureAwait(false);
Current = new Page(_info, data);
_info.Page++;
@@ -71,7 +73,11 @@ namespace Discord
return true;
}
- public void Dispose() { Current = null; }
+ public ValueTask DisposeAsync()
+ {
+ Current = null;
+ return default;
+ }
}
}
}
diff --git a/src/Discord.Net.Examples/Discord.Net.Examples.csproj b/src/Discord.Net.Examples/Discord.Net.Examples.csproj
index b02d2e6d8..ec0253428 100644
--- a/src/Discord.Net.Examples/Discord.Net.Examples.csproj
+++ b/src/Discord.Net.Examples/Discord.Net.Examples.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Discord.Net.Providers.WS4Net/Discord.Net.Providers.WS4Net.csproj b/src/Discord.Net.Providers.WS4Net/Discord.Net.Providers.WS4Net.csproj
index bfd0983ce..e143340e1 100644
--- a/src/Discord.Net.Providers.WS4Net/Discord.Net.Providers.WS4Net.csproj
+++ b/src/Discord.Net.Providers.WS4Net/Discord.Net.Providers.WS4Net.csproj
@@ -1,10 +1,10 @@
-
+
Discord.Net.Providers.WS4Net
Discord.Providers.WS4Net
An optional WebSocket client provider for Discord.Net using WebSocket4Net
- netstandard1.3
+ netstandard2.0
diff --git a/src/Discord.Net.Providers.WS4Net/WS4NetProvider.cs b/src/Discord.Net.Providers.WS4Net/WS4NetProvider.cs
index 166e767d0..b56f3b4f0 100644
--- a/src/Discord.Net.Providers.WS4Net/WS4NetProvider.cs
+++ b/src/Discord.Net.Providers.WS4Net/WS4NetProvider.cs
@@ -1,4 +1,4 @@
-using Discord.Net.WebSockets;
+using Discord.Net.WebSockets;
namespace Discord.Net.Providers.WS4Net
{
diff --git a/src/Discord.Net.Rest/API/Common/Game.cs b/src/Discord.Net.Rest/API/Common/Game.cs
index 2ec1e3846..d3a618697 100644
--- a/src/Discord.Net.Rest/API/Common/Game.cs
+++ b/src/Discord.Net.Rest/API/Common/Game.cs
@@ -35,6 +35,12 @@ namespace Discord.API
public Optional SessionId { get; set; }
[JsonProperty("Flags")]
public Optional Flags { get; set; }
+ [JsonProperty("id")]
+ public Optional Id { get; set; }
+ [JsonProperty("emoji")]
+ public Optional Emoji { get; set; }
+ [JsonProperty("created_at")]
+ public Optional CreatedAt { get; set; }
[OnError]
internal void OnError(StreamingContext context, ErrorContext errorContext)
diff --git a/src/Discord.Net.Rest/API/Common/Guild.cs b/src/Discord.Net.Rest/API/Common/Guild.cs
index 343d5b12c..56bd841ea 100644
--- a/src/Discord.Net.Rest/API/Common/Guild.cs
+++ b/src/Discord.Net.Rest/API/Common/Guild.cs
@@ -58,5 +58,7 @@ namespace Discord.API
public SystemChannelMessageDeny SystemChannelFlags { get; set; }
[JsonProperty("premium_subscription_count")]
public int? PremiumSubscriptionCount { get; set; }
+ [JsonProperty("preferred_locale")]
+ public string PreferredLocale { get; set; }
}
}
diff --git a/src/Discord.Net.Rest/API/Common/Message.cs b/src/Discord.Net.Rest/API/Common/Message.cs
index a5016f923..f20035685 100644
--- a/src/Discord.Net.Rest/API/Common/Message.cs
+++ b/src/Discord.Net.Rest/API/Common/Message.cs
@@ -50,6 +50,8 @@ namespace Discord.API
// sent with Rich Presence-related chat embeds
[JsonProperty("application")]
public Optional Application { get; set; }
+ [JsonProperty("message_reference")]
+ public Optional Reference { get; set; }
[JsonProperty("flags")]
public Optional Flags { get; set; }
}
diff --git a/src/Discord.Net.Rest/API/Common/MessageReference.cs b/src/Discord.Net.Rest/API/Common/MessageReference.cs
new file mode 100644
index 000000000..8c0f8fe14
--- /dev/null
+++ b/src/Discord.Net.Rest/API/Common/MessageReference.cs
@@ -0,0 +1,16 @@
+using Newtonsoft.Json;
+
+namespace Discord.API
+{
+ internal class MessageReference
+ {
+ [JsonProperty("message_id")]
+ public Optional MessageId { get; set; }
+
+ [JsonProperty("channel_id")]
+ public ulong ChannelId { get; set; }
+
+ [JsonProperty("guild_id")]
+ public Optional GuildId { get; set; }
+ }
+}
diff --git a/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs b/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs
index 9c519d3a8..6341b63b6 100644
--- a/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs
+++ b/src/Discord.Net.Rest/API/Rest/ModifyGuildParams.cs
@@ -32,5 +32,7 @@ namespace Discord.API.Rest
public Optional ExplicitContentFilter { get; set; }
[JsonProperty("system_channel_flags")]
public Optional SystemChannelFlags { get; set; }
+ [JsonProperty("preferred_locale")]
+ public string PreferredLocale { get; set; }
}
}
diff --git a/src/Discord.Net.Rest/Discord.Net.Rest.csproj b/src/Discord.Net.Rest/Discord.Net.Rest.csproj
index 75b69bd04..b9592f18d 100644
--- a/src/Discord.Net.Rest/Discord.Net.Rest.csproj
+++ b/src/Discord.Net.Rest/Discord.Net.Rest.csproj
@@ -4,16 +4,13 @@
Discord.Net.Rest
Discord.Rest
A core Discord.Net library containing the REST client and models.
- net46;netstandard1.3;netstandard2.0
- netstandard1.3;netstandard2.0
+ net461;netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1
-
-
-
-
+
diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
index d20aed431..7730a9cc3 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
@@ -68,6 +68,12 @@ namespace Discord.Rest
if (args.SystemChannelFlags.IsSpecified)
apiArgs.SystemChannelFlags = args.SystemChannelFlags.Value;
+ // PreferredLocale takes precedence over PreferredCulture
+ if (args.PreferredLocale.IsSpecified)
+ apiArgs.PreferredLocale = args.PreferredLocale.Value;
+ else if (args.PreferredCulture.IsSpecified)
+ apiArgs.PreferredLocale = args.PreferredCulture.Value.Name;
+
return await client.ApiClient.ModifyGuildAsync(guild.Id, apiArgs, options).ConfigureAwait(false);
}
/// is null.
diff --git a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
index cd142b184..e9e4d3290 100644
--- a/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
+++ b/src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using EmbedModel = Discord.API.GuildEmbed;
@@ -64,6 +65,11 @@ namespace Discord.Rest
public string Description { get; private set; }
///
public int PremiumSubscriptionCount { get; private set; }
+ ///
+ public string PreferredLocale { get; private set; }
+
+ ///
+ public CultureInfo PreferredCulture { get; private set; }
///
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
@@ -124,6 +130,8 @@ namespace Discord.Rest
SystemChannelFlags = model.SystemChannelFlags;
Description = model.Description;
PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault();
+ PreferredLocale = model.PreferredLocale;
+ PreferredCulture = new CultureInfo(PreferredLocale);
if (model.Emojis != null)
{
diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
index ef6d9a14c..75892defb 100644
--- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
@@ -11,6 +11,16 @@ namespace Discord.Rest
{
internal static class MessageHelper
{
+ ///
+ /// Regex used to check if some text is formatted as inline code.
+ ///
+ private static readonly Regex InlineCodeRegex = new Regex(@"[^\\]?(`).+?[^\\](`)", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+ ///
+ /// Regex used to check if some text is formatted as a code block.
+ ///
+ private static readonly Regex BlockCodeRegex = new Regex(@"[^\\]?(```).+?[^\\](```)", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
/// Only the author of a message may modify the message.
/// Message content is too long, length must be less or equal to .
public static async Task ModifyAsync(IMessage msg, BaseDiscordClient client, Action func,
@@ -112,9 +122,6 @@ namespace Discord.Rest
int index = 0;
var codeIndex = 0;
- var inlineRegex = new Regex(@"[^\\]?(`).+?[^\\](`)", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
- var blockRegex = new Regex(@"[^\\]?(```).+?[^\\](```)", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
-
// checks if the tag being parsed is wrapped in code blocks
bool CheckWrappedCode()
{
@@ -125,7 +132,7 @@ namespace Discord.Rest
// loop through all code blocks that are before the start of the tag
while (codeIndex < index)
{
- var blockMatch = blockRegex.Match(text, codeIndex);
+ var blockMatch = BlockCodeRegex.Match(text, codeIndex);
if (blockMatch.Success)
{
if (EnclosedInBlock(blockMatch))
@@ -136,7 +143,7 @@ namespace Discord.Rest
continue;
return false;
}
- var inlineMatch = inlineRegex.Match(text, codeIndex);
+ var inlineMatch = InlineCodeRegex.Match(text, codeIndex);
if (inlineMatch.Success)
{
if (EnclosedInBlock(inlineMatch))
diff --git a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
index 29a9c9bd2..f457f4f7a 100644
--- a/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
@@ -62,6 +62,8 @@ namespace Discord.Rest
public MessageActivity Activity { get; private set; }
///
public MessageApplication Application { get; private set; }
+ ///
+ public MessageReference Reference { get; private set; }
internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source)
: base(discord, id)
@@ -108,6 +110,17 @@ namespace Discord.Rest
};
}
+ if(model.Reference.IsSpecified)
+ {
+ // Creates a new Reference from the API model
+ Reference = new MessageReference
+ {
+ GuildId = model.Reference.Value.GuildId,
+ ChannelId = model.Reference.Value.ChannelId,
+ MessageId = model.Reference.Value.MessageId
+ };
+ }
+
if (model.Reactions.IsSpecified)
{
var value = model.Reactions.Value;
diff --git a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
index 4d164df96..e265f991f 100644
--- a/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
+++ b/src/Discord.Net.Rest/Extensions/EntityExtensions.cs
@@ -5,6 +5,13 @@ namespace Discord.Rest
{
internal static class EntityExtensions
{
+ public static IEmote ToIEmote(this API.Emoji model)
+ {
+ if (model.Id.HasValue)
+ return model.ToEntity();
+ return new Emoji(model.Name);
+ }
+
public static GuildEmote ToEntity(this API.Emoji model)
=> new GuildEmote(model.Id.Value,
model.Name,
diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj
index ddd3b7954..26a249097 100644
--- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj
+++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj
@@ -4,15 +4,12 @@
Discord.Net.WebSocket
Discord.WebSocket
A core Discord.Net library containing the WebSocket client and models.
- net46;netstandard1.3;netstandard2.0
- netstandard1.3;netstandard2.0
+ net461;netstandard2.0;netstandard2.1
+ netstandard2.0;netstandard2.1
true
-
-
-
diff --git a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
index cd0ab3db2..054348ef1 100644
--- a/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
+++ b/src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
@@ -5,6 +5,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -105,6 +106,11 @@ namespace Discord.WebSocket
public string Description { get; private set; }
///
public int PremiumSubscriptionCount { get; private set; }
+ ///
+ public string PreferredLocale { get; private set; }
+
+ ///
+ public CultureInfo PreferredCulture { get; private set; }
///
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
@@ -374,6 +380,8 @@ namespace Discord.WebSocket
SystemChannelFlags = model.SystemChannelFlags;
Description = model.Description;
PremiumSubscriptionCount = model.PremiumSubscriptionCount.GetValueOrDefault();
+ PreferredLocale = model.PreferredLocale;
+ PreferredCulture = new CultureInfo(PreferredLocale);
if (model.Emojis != null)
{
diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
index ae42d9d61..7900b7ee7 100644
--- a/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
+++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
@@ -53,6 +53,9 @@ namespace Discord.WebSocket
///
public MessageApplication Application { get; private set; }
+ ///
+ public MessageReference Reference { get; private set; }
+
///
/// Returns all attachments included in this message.
///
@@ -140,6 +143,17 @@ namespace Discord.WebSocket
PartyId = model.Activity.Value.PartyId.Value
};
}
+
+ if (model.Reference.IsSpecified)
+ {
+ // Creates a new Reference from the API model
+ Reference = new MessageReference
+ {
+ GuildId = model.Reference.Value.GuildId,
+ ChannelId = model.Reference.Value.ChannelId,
+ MessageId = model.Reference.Value.MessageId
+ };
+ }
}
///
diff --git a/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs b/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs
index fd91ba987..bad72aaea 100644
--- a/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs
+++ b/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs
@@ -1,3 +1,5 @@
+using Discord.Rest;
+using System;
using System.Collections.Immutable;
using System.Linq;
@@ -7,6 +9,19 @@ namespace Discord.WebSocket
{
public static IActivity ToEntity(this API.Game model)
{
+ // Custom Status Game
+ if (model.Id.IsSpecified)
+ {
+ return new CustomStatusGame()
+ {
+ Type = ActivityType.CustomStatus,
+ Name = model.Name,
+ State = model.State.IsSpecified ? model.State.Value : null,
+ Emote = model.Emoji.IsSpecified ? model.Emoji.Value.ToIEmote() : null,
+ CreatedAt = DateTimeOffset.FromUnixTimeMilliseconds(model.CreatedAt.Value),
+ };
+ }
+
// Spotify Game
if (model.SyncId.IsSpecified)
{
diff --git a/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj b/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj
index 58282d85b..f1db66363 100644
--- a/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj
+++ b/src/Discord.Net.Webhook/Discord.Net.Webhook.csproj
@@ -4,7 +4,7 @@
Discord.Net.Webhook
Discord.Webhook
A core Discord.Net library containing the Webhook client and models.
- netstandard1.3
+ netstandard2.0;netstandard2.1
diff --git a/src/Discord.Net/Discord.Net.nuspec b/src/Discord.Net/Discord.Net.nuspec
index 3aa0d6add..4b7717e58 100644
--- a/src/Discord.Net/Discord.Net.nuspec
+++ b/src/Discord.Net/Discord.Net.nuspec
@@ -13,21 +13,21 @@
false
https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png
-
+
-
-
+
+
-
+
diff --git a/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj b/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj
index 1ee986e8a..bc587657c 100644
--- a/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj
+++ b/test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.1
+ netcoreapp3.0
false
@@ -15,10 +15,13 @@
-
-
-
-
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/test/Discord.Net.Analyzers.Tests/Extensions/AppDomainPolyfill.cs b/test/Discord.Net.Analyzers.Tests/Extensions/AppDomainPolyfill.cs
deleted file mode 100644
index 729bc385c..000000000
--- a/test/Discord.Net.Analyzers.Tests/Extensions/AppDomainPolyfill.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.Linq;
-using System.Reflection;
-using Microsoft.DotNet.PlatformAbstractions;
-using Microsoft.Extensions.DependencyModel;
-
-namespace System
-{
- /// Polyfill of the AppDomain class from full framework.
- internal class AppDomain
- {
- public static AppDomain CurrentDomain { get; private set; }
-
- private AppDomain()
- {
- }
-
- static AppDomain()
- {
- CurrentDomain = new AppDomain();
- }
-
- public Assembly[] GetAssemblies()
- {
- var rid = RuntimeEnvironment.GetRuntimeIdentifier();
- var ass = DependencyContext.Default.GetRuntimeAssemblyNames(rid);
-
- return ass.Select(xan => Assembly.Load(xan)).ToArray();
- }
- }
-}
\ No newline at end of file
diff --git a/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj b/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj
index cd4aafac0..c571059ef 100644
--- a/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj
+++ b/test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj
@@ -1,4 +1,4 @@
-
+
netcoreapp2.1
@@ -15,9 +15,12 @@
-
-
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj b/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj
index 4a7898b14..357bf9531 100644
--- a/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj
+++ b/test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj
@@ -1,7 +1,7 @@
-
+
- netcoreapp2.1
+ netcoreapp3.0
false
@@ -13,9 +13,12 @@
-
-
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs
index 573ca57c3..8b4e8b0d0 100644
--- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs
+++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Text;
using System.Threading.Tasks;
using Discord.Audio;