Discord.NET: UserJoined Event not being called - c#

I'm building a Discord bot using Discord.NET which is supposed to report a user joining, leaving, being kicked and being banned to a mod/admin-only auditing channel, except I can't get the relevant function to trigger when a user joins the guild.
I removed my message sending code and replaced it with a console output to determine whether or not the problem is the event not triggering or the send message request not working and found the event wasn't being triggered.
I've enabled all the intents in the Bot management console.
I've added intents according to the documentation:
var socketConfig = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.GuildMembers | GatewayIntents.GuildBans
};
_client = new DiscordSocketClient(socketConfig);
I've then registered the event: (Note: _client = client; is used before this)
client.UserJoined += UserJoined;
And finally written the function to be triggered:
public Task UserJoined(SocketGuildUser user)
{
Console.Write("User ");
Console.Write(user.Username);
Console.WriteLine(" joined.");
return Task.CompletedTask;
}
Is there anything I've not done or done wrong here? I've spent about two days on this with absolutely no idea what the problem is, everything seems to point to me doing everything right yet I'm unable to receive this event from Discord.
Every change I've made I've additionally tried removing and re-adding the bot to my test server. I also don't receive any kind of message similar to [12/8/2018 10:01:30 PM at Gateway] Received Dispatch (GUILD_MEMBER_ADD) as mentioned in this post.
I've included my full Program.cs below:
using System;
using Discord;
using Discord.Net;
using Discord.Commands;
using Discord.WebSocket;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.DependencyInjection;
using BanBot2.Bot.Services;
namespace BanBot2.Bot
{
class Program
{
// setup our fields we assign later
private readonly IConfiguration _iconfig;
private DiscordSocketClient _client;
static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult();
public Program()
{
var socketConfig = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.GuildMembers | GatewayIntents.GuildBans
};
_client = new DiscordSocketClient(socketConfig);
// create the configuration
var _builder = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile(path: "application.json");
// build the configuration and assign to _config
_iconfig = _builder.Build();
}
public async Task MainAsync()
{
// call ConfigureServices to create the ServiceCollection/Provider for passing around the services
using (var services = ConfigureServices())
{
// get the client and assign to client
// you get the services via GetRequiredService<T>
var client = services.GetRequiredService<DiscordSocketClient>();
_client = client;
// setup logging and the ready event
client.Log += LogAsync;
client.Ready += ReadyAsync;
client.UserJoined += UserJoined;
services.GetRequiredService<CommandService>().Log += LogAsync;
// this is where we get the Token value from the configuration file, and start the bot
await client.LoginAsync(TokenType.Bot, _iconfig["Token"]);
await client.StartAsync();
// we get the CommandHandler class here and call the InitializeAsync method to start things up for the CommandHandler service
await services.GetRequiredService<CommandHandler>().InitializeAsync();
await Task.Delay(-1);
}
}
public Task UserJoined(SocketGuildUser user)
{
Console.Write("User #");
Console.Write(user.Username);
Console.WriteLine(" joined.");
return Task.CompletedTask;
}
private Task LogAsync(LogMessage log)
{
Console.WriteLine(log.ToString());
return Task.CompletedTask;
}
private Task ReadyAsync()
{
Console.WriteLine($"Connected as -> [{_client.CurrentUser}] :)");
return Task.CompletedTask;
}
// this method handles the ServiceCollection creation/configuration and builds out the service provider we can call on later
private ServiceProvider ConfigureServices()
{
// this returns a ServiceProvider that is used later to call for those services
// we can add types we have access to here, hence adding the new using statement:
// using BanBot2.Bot.Services;
// the config we build is also added, which comes in handy for setting the command prefix!
return new ServiceCollection()
.AddSingleton(_iconfig)
.AddSingleton<DiscordSocketClient>()
.AddSingleton<CommandService>()
.AddSingleton<CommandHandler>()
.BuildServiceProvider();
}
}
}

You create an instance of DiscordSocketClient and include the appropriate DiscordSocketConfig
//good
var socketConfig = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.GuildMembers | GatewayIntents.GuildBans
};
_client = new DiscordSocketClient(socketConfig);
However, in ConfigureServices you should be adding the DiscordSocketClient that you created previously to the ServiceProvider. Instead you do this
//bad
.AddSingleton<DiscordSocketClient>()
while what you should have done is
//good
.AddSingleton(_client)
Because you didn't add an instance of the client to your service provider in configure services, retrieving the client from the service provider will actually instantiate a new DiscordSocketClient as one does not yet exist in the provider.
var client = services.GetRequiredService<DiscordSocketClient>();
tl;dr - ensure you are only using a single instance of DiscordSocketClient. This instance should be configured with the appropriate intents.

Related

Unity Remote Config 3.X scriptting correctly for remotly configs

Some days ago I meet a new problem with my game in Unity and this problem is about Remote Config. For some time I wanted to implement a little system with what I want to make some change about values and some things in my game remotly. Now my little problem is this: On internet or on most sites I see old configuration in scripts with RemoteConfig (principal thing (i don't know how I can say) in scripting with what you can make script and with what you can make connection between game and Unity Servers with online datas), and now with versions: 3.X for remote config The struct of file is complete different (with different services) and I understood very broadly how it works but with my attempts all is okey-sh (ok but maybe not) but I have sometimes some errors about my scripts with this component, Remote Config. I.E. I have in my script an warnings about authentification and core service.
Now bellow I put my script and Unity sample to see an error and I want to help me with solution for my problem to make a good script for my game to make changes remotly
P.S.: I want make a little note. I am logged in Unity with my account and connection between Unity and Unity servers is ok i guess because datas about online datas is correct (strings and boools) and enviroment id is the same with enviroment Id in dashboard in browser.
P.S.2: I have all time internet connection for all the same features in unity
Help me please, thx.
My script:
using System.Threading.Tasks;
using Unity.Services.RemoteConfig;
using Unity.Services.Authentication;
using Unity.Services.Core;
using UnityEngine;
using UnityEngine.SceneManagement;
public class RemoteConfigGame : MonoBehaviour
{
public struct userAttributes { }
public struct appAttributes { }
public bool existUpdate;
public bool existMaintainance;
[SerializeField] GameManager gameManager;
[HideInInspector] string cloudVersion;
async Task InitializeRemoteConfigAsync()
{
// initialize handlers for unity game services
await UnityServices.InitializeAsync();
// remote config requires authentication for managing environment information
if (!AuthenticationService.Instance.IsSignedIn)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
}
public void Awake()
{
RemoteConfigService.Instance.FetchCompleted += ApplyRemoteSettings;
RemoteConfigService.Instance.FetchConfigs(new userAttributes(), new appAttributes());
}
void ApplyRemoteSettings(ConfigResponse configResponse)
{
switch (configResponse.requestOrigin)
{
case ConfigOrigin.Default:
Debug.Log("Default values will be returned");
break;
case ConfigOrigin.Cached:
Debug.Log("Cached values loaded");
break;
case ConfigOrigin.Remote:
Debug.Log("Remote Values changed");
Debug.Log("RemoteConfigService.Instance.appConfig fetched: " + RemoteConfigService.Instance.appConfig.config.ToString());
break;
}
existMaintainance = RemoteSettings.GetBool("isMaintainance");
existUpdate = RemoteSettings.GetBool("isUpdate");
cloudVersion = RemoteSettings.GetString("publishVersion");
}
void Update()
{
if (existUpdate && !existMaintainance)
{
if (gameManager.wasUpdatePannel == false && gameManager.manuPannel.activeInHierarchy)
{
if ((cloudVersion != gameManager.versionString) && gameManager.wasLoaded == true)
{
gameManager.updatePannel.SetActive(true);
gameManager.manuPannel.SetActive(false);
gameManager.versionForUpToDate = cloudVersion;
}
}
else
{
gameManager.updatePannel.SetActive(false);
gameManager.manuPannel.SetActive(true);
}
}
else if ((existUpdate && existMaintainance) || (!existUpdate && existMaintainance) )
{
SceneManager.LoadScene("Maintainance");
}
}
void OnDestroy()
{
RemoteConfigService.Instance.FetchCompleted -= ApplyRemoteSettings;
}
}
Unity Sample:
// -----------------------------------------------------------------------------
//
// This sample example C# file can be used to quickly utilise usage of Remote Config APIs
// For more comprehensive code integration, visit https://docs.unity3d.com/Packages/com.unity.remote-config#latest
//
// -----------------------------------------------------------------------------
using System.Threading.Tasks;
using Unity.Services.RemoteConfig;
using Unity.Services.Authentication;
using Unity.Services.Core;
using UnityEngine;
public class ExampleSample : MonoBehaviour
{
public struct userAttributes {}
public struct appAttributes {}
async Task InitializeRemoteConfigAsync()
{
// initialize handlers for unity game services
await UnityServices.InitializeAsync();
// options can be passed in the initializer, e.g if you want to set analytics-user-id use two lines from below:
// var options = new InitializationOptions().SetOption("com.unity.services.core.analytics-user-id", "my-user-id-123");
// await UnityServices.InitializeAsync(options);
// remote config requires authentication for managing environment information
if (!AuthenticationService.Instance.IsSignedIn)
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
}
async Task Start()
{
// initialize Unity's authentication and core services, however check for internet connection
// in order to fail gracefully without throwing exception if connection does not exist
if (Utilities.CheckForInternetConnection())
{
await InitializeRemoteConfigAsync();
}
RemoteConfigService.Instance.FetchCompleted += ApplyRemoteSettings;
RemoteConfigService.Instance.FetchConfigs(new userAttributes(), new appAttributes());
// -- Example on how to fetch configuration settings using filter attributes:
// var fAttributes = new filterAttributes();
// fAttributes.key = new string[] { "sword","cannon" };
// RemoteConfigService.Instance.FetchConfigs(new userAttributes(), new appAttributes(), fAttributes);
// -- Example on how to fetch configuration settings if you have dedicated configType:
// var configType = "specialConfigType";
// RemoteConfigService.Instance.FetchConfigs(configType, new userAttributes(), new appAttributes());
// -- Configuration can be fetched with both configType and fAttributes passed
// RemoteConfigService.Instance.FetchConfigs(configType, new userAttributes(), new appAttributes(), fAttributes);
// -- All examples from above will also work asynchronously, returning Task<RuntimeConfig>
// await RemoteConfigService.Instance.FetchConfigsAsync(new userAttributes(), new appAttributes());
// await RemoteConfigService.Instance.FetchConfigsAsync(new userAttributes(), new appAttributes(), fAttributes);
// await RemoteConfigService.Instance.FetchConfigsAsync(configType, new userAttributes(), new appAttributes());
// await RemoteConfigService.Instance.FetchConfigsAsync(configType, new userAttributes(), new appAttributes(), fAttributes);
}
void ApplyRemoteSettings(ConfigResponse configResponse)
{
switch (configResponse.requestOrigin)
{
case ConfigOrigin.Default:
Debug.Log("Default values will be returned");
break;
case ConfigOrigin.Cached:
Debug.Log("Cached values loaded");
break;
case ConfigOrigin.Remote:
Debug.Log("Remote Values changed");
Debug.Log("RemoteConfigService.Instance.appConfig fetched: " + RemoteConfigService.Instance.appConfig.config.ToString());
break;
}
}
}
With my code I have 2 warnings and i want to fix
Core Service not initialized.
Request might result in empty or incomplete response
Please refer to https://docs.unity3d.com/Packages/com.unity.remote-config#3.0/manual/CodeIntegration.html
and
Auth Service not initialized.
Request might result in empty or incomplete response
Please refer to https://docs.unity3d.com/Packages/com.unity.remote-config#3.0/manual/CodeIntegration.html

Do not collect child opentelemetry trace when parent trace is not recorded

I'm in the middle of introducing distributed tracing in a microservice app. All my services have the tracing enabled and everything works fine. But...
My app runs on a K8S cluster, so that cluster makes a lot of call to health endpoint. A lot is a lot. for the moment when nothing happens on a setup, I get 50Gb of trace recorder per day.
trace lock like this: one trace for the /health call and one children trace for a database call (call to check if db is available)
So, i decided to not record Health trace this is easily done by
// in startup
tracerProviderBuilder.AddAspNetCoreInstrumentation(x => x.Filter = AspnetCoreOtelFilter.Filter)
//the filter
public static class AspnetCoreOtelFilter
{
public static bool Filter(HttpContext httpContext)
{
if (httpContext.Request.Path == "/health/liveness")
return false;
if (httpContext.Request.Path == "/health/readiness")
return false;
return true;
}
}
as a result, I don't see all the health trace in my APM, anymore, but I keep receiving the trace regarding the log in DB
I was expecting that ParentBasedSampler (https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry/Trace/ParentBasedSampler.cs) would do the magic, but it's not the case.
Do you have any idea.
Thx for your help
Here is my test class:
[TestMethod, Ignore("Didn't succeed to avoid child message for now")]
public async Task HealthWithSubTrace_NoTracing()
{
var exportedItems = new List<Activity>();
var factory = new WebApplicationFactory<Program>();
using (var client = factory.WithWebHostBuilder(builder =>
builder.ConfigureTestServices(serviceCollection => ConfigureInMemoryExporterForOpenTelemetry()).CreateClient())
{
using var response = await client.GetAsync((string?)"/health/details").ConfigureAwait(false);
response.EnsureSuccessStatusCode();
WaitForActivityExport(exportedItems, 1);
}
Assert.AreEqual(0, exportedItems.Count);
}
//OTEL configuration is this
tracerProviderBuilder
.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService(serviceName))
.SetSampler(sp => new ParentBasedSampler(new AlwaysOnSampler())
.AddAspNetCoreInstrumentation(x => x.Filter = AspnetCoreOtelFilter.Filter)
.AddHttpClientInstrumentation()
.AddProcessor<K8STagsProcessor>()
.AddSource(OpenTelemetrySources.Npgsql)
.AddSource(Program.source.Name);
//with program defined as this
public class Program
{
public static readonly ActivitySource source = new("OpenTelemtry.Test.App");
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigurePhoenixHealth()
.AddHealthChecks().AddCheck(HealthConstants.Self, () => HealthCheckResult.Healthy());
var app = builder.Build();
app.UsePhoenixHealth();
app.MapGet("/health/details", () =>
{
using var activity = source.StartActivity("health.detail");
return "all fine";
});
app.Run();
}
}

Azure Event Hubs : QuotaExceededException : 4999 handles limit

I am using Azure Event Hub library for C# in WebApi App. And I got this exception on message sending:
"Message":"An error has occurred.",
"ExceptionMessage":"Cannot allocate more handles to the current session or connection. The maximum number of handles allowed is 4999. Please free up resources and try again., referenceId: d975f39c71a14ae5915c9adca322e110_G15"
"ExceptionType":"Microsoft.ServiceBus.Messaging.QuotaExceededException"
I thought that instantiantion of EventHubProducerClient one time and reusing it instead of creating its instance on each message sending (with IAsyncDisposable pattern) will help as mentioned here
EventHub Exception :Cannot allocate more handles to the current session or connection. But it did not.
I believe there might be some more global issue. Might be missing something.
I am using single event hub with 7 consumer groups each of which is used by separate web application (single); well actually there is additional consumer group ($Default) but it is not used;
For receiving messages I use EventProcessorClient;
I use Azure.Messaging.EventHubs 5.2.0 and Azure.Messaging.EventHubs.Processor 5.2.0 packages;
Here is the whole code (did everything according to quickstart):
public class EventHubService : SubscriberBase
{
private readonly Action<string> errorHandler;
private readonly BlobContainerClient blobContainerClient;
private readonly EventProcessorClient eventProcessorClient;
private readonly EventHubProducerClient eventHubProducerClient;
private readonly int eventsToCheckpoint;
private readonly Timer checkpointTimer;
private int eventsSinceLastCheckpoint;
private bool shouldUpdateCheckpoint;
public EventHubService(EventHubSettings settings, Action<string> errorHandler) : base()
{
this.errorHandler = errorHandler;
eventHubProducerClient = new EventHubProducerClient(settings.ConnectionString, settings.EventHubName);
if (!String.IsNullOrWhiteSpace(settings.GroupId))
{
eventManager = new EventManager();
blobContainerClient = new BlobContainerClient(settings.StorageConnectionString, settings.BlobContainerName);
eventProcessorClient = new EventProcessorClient(blobContainerClient, settings.GroupId, settings.ConnectionString, settings.EventHubName);
eventsToCheckpoint = settings.EventsToUpdateCheckpoint;
checkpointTimer = new Timer(settings.IntervalToUpdateCheckpoint.TotalMilliseconds);
checkpointTimer.Elapsed += (sender, eventArgs) => shouldUpdateCheckpoint = true;
}
}
public override void Start()
{
eventProcessorClient.ProcessErrorAsync += HandleError;
eventProcessorClient.ProcessEventAsync += ProcessEventData;
eventProcessorClient.StartProcessingAsync().Wait();
checkpointTimer.Start();
}
public override async Task Stop()
{
try
{
checkpointTimer.Stop();
await eventProcessorClient.StopProcessingAsync();
}
finally
{
eventProcessorClient.ProcessEventAsync -= ProcessEventData;
eventProcessorClient.ProcessErrorAsync -= HandleError;
}
}
public override async Task Publish(string topic, JObject message)
{
using (EventDataBatch eventBatch = await eventHubProducerClient.CreateBatchAsync())
{
var #event = new Event(topic, message);
string json = #event.ToString(Formatting.None);
byte[] bytes = Encoding.UTF8.GetBytes(json);
var eventData = new EventData(bytes);
eventBatch.TryAdd(eventData);
await eventHubProducerClient.SendAsync(eventBatch);
}
}
private async Task ProcessEventData(ProcessEventArgs eventArgs)
{
if (eventArgs.CancellationToken.IsCancellationRequested)
{
return;
}
if (++eventsSinceLastCheckpoint >= eventsToCheckpoint)
{
eventsSinceLastCheckpoint = 0;
shouldUpdateCheckpoint = true;
}
if (shouldUpdateCheckpoint)
{
await eventArgs.UpdateCheckpointAsync();
shouldUpdateCheckpoint = false;
}
string json = Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray());
var #event = new Event(json);
eventManager.TryRaise(#event);
}
private Task HandleError(ProcessErrorEventArgs eventArgs)
{
if (!eventArgs.CancellationToken.IsCancellationRequested)
{
errorHandler.Invoke($"[P:{eventArgs.PartitionId}][O:{eventArgs.Operation}] {eventArgs.Exception.Message}");
}
return Task.CompletedTask;
}
}
I have found some info in Service Bus Quotas like:
Number of concurrent receive requests on a queue, topic, or subscription entity (5000).
Subsequent receive requests are rejected, and an exception is received
by the calling code. This quota applies to the combined number
of concurrent receive operations across all subscriptions on a topic.
But still can't figure how to deal with it.
Please help.
Thanks.
This is indeed the answer EventHub Exception :Cannot allocate more handles to the current session or connection.
I did similar "fix" for Azure Event Hub library for NET Core but I have forgotten that I am also using Azure Event Hub library for NET Framework!
So I have instantiated EventHubProducerClient one time and reusing it now.
Seems working fine.
My bad. Was not attentive enough.
In my case, except creating only one instance of Client, use only one instance of sender.
I used method CreateSender each time when send a messsage, it also generates an exception

Unable to return a value from SignalR Client from a different method

I'm working on a Winforms app that executes SQL Procedures through a SignalR client. I'm relatively new to using SignalR and am still wrapping my head around it.
I start off by running my connection method to establish a connection with my SignalR service. I have two addresses configured ready for when I puslish but the DEV configuration leads to the SignalR service I am hosting locally.
Connection to SignalR (ConnectHub)
private async Task ConnectHub()
{
string hubAddress = "";
#if DEBUG
HubAddress = ConfigurationManager.AppSettings["HubAddress_DEV"];
#else
HubAddress = ConfigurationManager.AppSettings["HubAddress_PROD"];
#endif
if (string.IsNullOrEmpty(hubAddress))
{
MessageBox.Show("Hub Address is missing from configuration.");
}
ConnectionHandler.Client = new HubClient(hubAddress, "MyHub");
ConnectionHandler.Client.MyAlert += ConnectionHandler.ClientOnMyAlert;
ConnectionHandler.Client.ServerErrorEvent += ConnectionHandler.ClientOnServerErrorEvent;
await ConnectionHandler.Client.Connect(new List<string>() {
VehicleInfo.ThisVehicle.WarehouseCode,
VehicleInfo.ThisVehicle.VehicleName
});
}
My client is stored globally in my ConnectionHandler class where my event handlers are also kept. (I have breakpoints on these as I have not implemented them yet)
ConnectionHandler Class
public static class ConnectionHandler
{
public static HubClient Client { get; set; }
public static void ClientOnServerErrorEvent(string error)
{
throw new NotImplementedException(); //Currently not implemented
}
public static async Task ClientOnMyAlert(EnumMyAlertType alerttype, string message, Exception exception)
{
await Task.Yield(); //Currently not implemented
}
}
When I call the code to Invoke the procedure in my SignalR client, it returns a DataTable to me which is the intended result.
Call to SignalR
await ConnectHub();
DataTable dt = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>(
"FetchStatuses",
new object[0]); //This call works as intended and returns a populated DataTable
StatusInfo = new CStatuses();
All the above code is currently done on the main form, however I wanted to move this call to SignalR into a constructor to try and tidy things up.
The problem comes when I try to move this call into another method, the program hangs as I don't think it has received the return value from SignalR, I have placed a breakpoint beneath it and it is not reached. A TryCatch reveals nothing as it hangs within the "Try" with no exception.
Calling from contructor
public CStatuses()
{
Statuses = new List<CStatus>();
var dataTable = ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0])
.Result; //My program hangs on this line and proceeds no further
I am at a loss as to why it is doing this when I can get a value from the client from the form and when other members of my team have tried to do the same thing they can make a call to SignalR also from a different method.
Does anyone have any ideas as to how I can make this work?
I realize this has gotten quite long but if I can elaborate on things please let me know
FIXED CODE THANKS TO SOLUTION:
I have moved the code from my CStatuses constructor into a new async method within the same class and called it after initialization. This removes the need for .Result and appears to solve the problem for me.
public async Task PopulateStatuses()
{
var dataTable = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0]);
Statuses = new List<CStatus>();
foreach (DataRow row in dataTable.Rows)
{
var status = new CStatus
{
StatusId = Common.Utility.GetInt16Value(row["StatusID"]),
StatusCode = Common.Utility.GetStringValue(row["StatusCode"]),
Description = Common.Utility.GetStringValue(row["Description"])
};
Statuses.Add(status);
}
}
You are running into a deadlock with the .Result call, I would suggest creating an async method in the CStatuses class and after you initialize your CStatuses class call the websocket for data.

Discord bot running, but will not connect to server

I've been trying to swap over my code from the 0.9.6 Discord.NET API to the new 1.0.1 API, and it's basically calling for a complete restructure to my code. But I've been having some trouble actually getting the bot up and running first of all.
I set up the code body according to the guide linked here
And while it runs without error, the bot itself is not appearing online in my server.
And before you ask, I had in fact replaced "Bot token here" with the actual bot token.
namespace DiscordBot{
public class Program
{
private CommandService commands;
private DiscordSocketClient client;
private IServiceProvider services;
static void Main(string[] args) => new Program().Start().GetAwaiter().GetResult();
public async Task Start()
{
client = new DiscordSocketClient();
commands = new CommandService();
string token = "<token>";
services = new ServiceCollection()
.BuildServiceProvider();
await InstallCommands();
await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync();
await Task.Delay(-1);
}
public async Task InstallCommands()
{
// Hook the MessageReceived Event into our Command Handler
client.MessageReceived += HandleCommand;
// Discover all of the commands in this assembly and load them.
await commands.AddModulesAsync(Assembly.GetEntryAssembly());
}
public async Task HandleCommand(SocketMessage messageParam)
{
// Don't process the command if it was a System Message
var message = messageParam as SocketUserMessage;
if (message == null) return;
// Create a number to track where the prefix ends and the command begins
int argPos = 0;
// Determine if the message is a command, based on if it starts with '!' or a mention prefix
if (!(message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(client.CurrentUser, ref argPos))) return;
// Create a Command Context
var context = new CommandContext(client, message);
// Execute the command. (result does not indicate a return value,
// rather an object stating if the command executed successfully)
var result = await commands.ExecuteAsync(context, argPos, services);
if (!result.IsSuccess)
await context.Channel.SendMessageAsync(result.ErrorReason);
}
}
}
And then for the MyBot.cs class
namespace DiscordBot
{
class MyBot : ModuleBase
{
private CommandService _service;
public MyBot(CommandService service)
{
_service = service;
}
}
}
The first thing you might want to do is add some logging to your bot.
As your code might be correct, but discord could be rejecting your connection for any amount of reason.
After await client.StartAsync(); add
client.Log += (msg) => {return Console.WriteLine(${msg.ToString()}");};`
This will output the message your receive from your client to the console.
Now you also need to configure which message should be send to this event. This can be done when creating your DiscordClient(). So instead of client = new DiscordSocketClient(); You could use
client = new DiscordSocketClient(
new DiscordSocketConfig()
{
LogLevel = LogSeverity.Verbose
}
);
Verbose should give you all the information you need. However you could also use LogSeverity.Debug instead, which is the highest available logging, and therefore would give you all messages.
Now that you have some feedback in your console, go and see what concrete errors you are having.
Also I would recommend first completing the your first bot part of the linked tutorial, instead of stepping into the commands directly. Once you got this working, you can continue onwards

Categories

Resources