#FAQ says CommandsNext will be deprecated, and I should use Commands, but I cant find that library
1 messages · Page 1 of 1 (latest)
ok, thank you, how is the stability of v5 builds?
more stable that our "stable" version
ok, thanks for the quick response, will give that a try then
does there exist any examples using v5 commands anywhere, its not the same setup as how commandsnext work?
cc @crisp palm
Nightly builds are released per commit to the master repository
Usually we test our commits in the PR stage before they're merged
We only make official releases when there aren't any outstanding bugs or features waiting to be merged to the master branch
yeah, its similar to how we have made our release channel be the defactor "release" for our civ4 mod, we almost never release properly
(really, unstable/stable here mostly refers to the API surface, reliability is about the same, if anything nightly tends to be more stable because we actually fix bugs there)
civ 4, excellent
it goes to release branch which pushes to svn for us, and then people use svn to keep mod updated
Honestly I'm thinking about just merging what we have now
Im part of the team that works on Caveman2Cosmos
I'm too burnt out to write any more articles
And other people are in desperate need of them
sure
I'm gonna make a few final touches then we'll merge
I have no idea what that is but congratulations
Ill get this v5 version into my self built "discordbot host" that uses IHostedService, and ill see how it flies. I run the bot as a hosted service addon to a webapi
Hmm
just a reference to how you handle releasing on master
Do you think you'd be able to make use of HTTP Interactions?
the bot I am building is a cs2 gather bot, I dont want to expose all commands through discord, such as adding gameservers and whatnot
I prefer to have that on rest api with admin panel, and authentication that way
Right right
I was more concerned about switching over the Discord commands you have right now to HTTP Interactions
(Briefly put: the only thing that changes is how they're received)
(and ideally how the original response is created, which leaks to the user if we don't by default integrate with some http server)
I am on my 5th? rebuild on the bot right now, but most of my commands call mediatr, the reason I wanted scope, is because then I can cache things like player information so I dont have to re-fetch playerdata, leaguedata, and so on over and over
the first thing I do when player calls a command is to verify that the player is signed up, has steamid and all these things, then check if gameservers are available, or a gather is being created, I have had to re-fetch that data atleast twice with the old way it worked
I can try making use of HTTP interactions, I just need to be pointed to the docs
and ill give it a whack
Unfortunately, I know not nearly enough about the inner workings of how the discord api works, beyond creating commands, and acting on those commands
They're not available yet unfortunately 😔
But when we do add them, we'll be adding them as a command processor
The only thing you'd have to change is literally a single line
I'll give it a try when they exist then
what is the advantage of HTTP interactions?
I'll let ya know when they do 
I can literally call the bot using https?
ok
I think the biggest issue for us is integration with other webservers
But... Maybe other extension methods might be able to fix that
¯_(ツ)_/¯
the advantage is that they're faster, more reliable, lighter on your ratelimits
ahh I see, because currently all commands are sent through websocket, if i understand it correctly
the disadvantage is that they're pretty hard to implement in a way that's both intuitive and unrestrictive
In theory, less resource intensive too
Yep
All events in general, which includes interactions
God I really want to start on the gateway rewrite
I have an alarming amount of experience creating services that are based on httpClient from actual work
I need to actually get familiar with how things work in the nitty gritty first though
We'd be using HttpListener or ASP.NET Core
Discord sends us http requests and we'd respond
so long as you don't stream at 4am for me my offer of discussing it live stands
ahh, so its all webhook based
:)
Yesn't?
big ty for help, I will give this a whirl, and maybe I can atleast create a library that will be able to just plug into .net core webapi
Discord sends up the http request (POST https://your-website.com/api/discord-interactions) and you respond like any other http request that your webserver handles
I hope I'm explaining it well lol
oh, I see, so in very simple terms, the bot would have controllers that handle all the discord interactions (minimal api kinda makes more sense)
yeah, i'd go minimal api route for that
because then you can set up the project having webapi, and all the endpoints can be just imported in your "addDiscordBot" service extension
have to use ngrok tunnel or other "fun" things to do testing of that though
Ah yeah that's true
I mean with how I want to do it you could just receive the interactions through the gateway
Your code won't change
Only the command processors used
I'm just glad I have something like this already setup via my VPN
https://oolunar.forsaken-borders.net/ points towards my laptop whenever it's connected 
It's great
what I would do for that to fly, atleast earlystage, is to require the bot to be attached to webapi, and then use minimalapi endpoints that is mapped to your services
and then bob should be your uncle relatively easily
I am actually pretty sure that, you can set that up inverse of how I set things up where the webapi is the startup project, and discordbot is launched by webapi
instead you could have discordbot be startup project, launch var builder = WebApplication.CreateBuilder() and then you run a IServiceCollection extension onto builder.Services that maps your minimal api endpoints
you should be cooking on gas pretty rapidly then, you would also then not need to worry about all the nitty gritty of actually handling the entire http request pipeline (that is ass)
the real trick is to let the webapplicationbuilder handle the ultimate creation of your servicecollection
##1820 :)
Issue #1820: v5 extensions and events design - akiraveliara
give me 30min, I am gonna see how v5 actually behaves when I set it up as hosted service, if it behaves well, I am gonna see if I can be creative
Runtime behavior hasn't changed too much. What has changed should be separated into a different API, with few exceptions
this has now turned into a howto send me off on a tangent thinking about a problem
but yeah, if possible i would stay well clear of trying to "redesign the wheel" when it comes to httpListener
I speak from experience in extensive amount of idiocy on that one, the http request handling pipeline in .net is robust, and probably could (should?) solve your usecase
(redesigning wheels that is)
oh yeah the foreach is just for shardedclient, because it runs multiple instances of the client, I get it now, never really thought about the difference until now
is there any reason to use DiscordClient intead of DiscordShardedClient? I see DiscordClient does not have .UseCommandsAsync
DiscordClient is a single shard
which is generally what you want if you don't plan on serving enough guilds to warrant multiple shards
yeah, I only ever plan to serve in my own server
its just DiscordClient doesnt have UseCommandsAsync
it has the sync version thereof
yeah, I found it
was just surprised that usecommands didnt have async in a single instance scenario
it doesn't need to
the only reason it's async on the sharded client is that it may make an API call to determine the amount of shards it should create
yeah I am just normally using async everywhere, I am starting to see that may not always be smart 😛
You don't know who I am and that's okay
🙂
I'm going to try to use existing solutions for the convenience of our users though
For once
No, I have long since come to terms, that even though, I am fairly bright, there is always someone out there with a better solution than whatever I have come up with, all I can do is come with ideas
The only reason why it's async is because we need to fetch the shard information before any extension is registered
Fuck
I assume using Task when not needed has some unneeded overhead?
quite a lot thereof
Aki can go more into depth about it but the rule of thumb is to use VT when possible
probably not enough for people to care
but i care :smile:
when code isn't actually async, just keeping it sync is best (unless otherwise mandated by other restrictions, like implementing an interface)
yeah, most of my operations are some async operation anyway, like fetching from or saving to db
when it can run async, i would generally use ValueTask where possible, but sticking to Task is also reasonable to avoid needing to understand how ValueTask works
(im sure whoever reviews my ratelimit PR will have fun with all the async ValueTask hacks in there)
ValueTask is so far, outside my wheelhouse
Oh my God
You suck
LMAO


public Task StartAsync(CancellationToken cancellationToken)
{
var commandsExtension = _discordClient.UseCommands(new CommandsConfiguration
{
ServiceProvider = _serviceProvider
});
commandsExtension.AddCommands(typeof(DiscordBotService).Assembly);
var textCommandProcessor = new TextCommandProcessor(new ()
{
PrefixResolver = new DefaultPrefixResolver("!").ResolvePrefixAsync
});
_ = commandsExtension.AddProcessorsAsync(textCommandProcessor);
return Task.CompletedTask;
}
should do fine, _serviceProvider is fetched from the serviceCollection, gotta start the bot in there as well,
attaching it to webapi like this:
public static IServiceCollection AddDiscordBot(this IServiceCollection services, IConfiguration configuration)
{
services.Configure<DiscordClientConfig>(configuration.GetSection(DiscordClientConfig.Section));
services.Configure<DiscordCommandServiceConfig>(configuration.GetSection(DiscordCommandServiceConfig.Section));
services.AddSingleton<DiscordBotService>();
services.AddHostedService(p => p.GetRequiredService<DiscordBotService>());
return services;
}
how do I create my own attributes with this setup? That I have not found yet
attributes as in pre-execution checks?
yeah
ok now i gotta figure out how to convert this:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class PlayerRegisteredAttribute : CheckBaseAttribute
{
public bool RegistrationRequired { get; set; }
public PlayerRegisteredAttribute(bool registrationRequired)
{
RegistrationRequired = registrationRequired;
}
public override async Task<bool> ExecuteCheckAsync(CommandContext ctx, bool help)
{
var mediator = ctx.Services.GetService(typeof(IMediator)) as IMediator;
var player = await mediator!.Send(new GetPlayerByDiscordIdRequest(ctx.User.Id));
return player.Success == RegistrationRequired;
}
}
to that
you make an attribute with just the property and constructor
and then you make a check impl that takes the mediator through regular DI and copy the body over
presently, you're made to return an error message, that might change to a result type whenever @crisp palm approves
ty for clarifying
now I only need to fuck it up twice before it works instead of the customary 5 times 😄
its exactly what I want though, because then I can do the registered check in the attribute, and store that player in a scoped service, that holds extended data about the call (player, what gather league and so on) without having to re-fetch it ad infinitum
what I used to have to do, was do the same fetch from db atleast once, maybe twice more, and same with the information about the league in the channel
yeah, improving the way it works with DI was one of the main reasons for this design
it was driving me mad how inefficient it was to constantly have to re-fetch this data
not to mention dealing with the fun and games of scopes and entity framework
I just realized, if you run custom implementation of httpListener, connecting this to existing webapi, wont that be a challenge since they will compete on port?
being 2 different instances of the httpListener
atleast in a prod environment where 80 and 443 is expected, unless some proxy shenanigans are done infront
another day of being very glad i don't do much web-related development 😄
public class PlayerIsRegisteredAttribute : ContextCheckAttribute
{
public bool RegistrationRequired { get; set; }
public PlayerIsRegisteredAttribute(bool registrationRequired = true) => RegistrationRequired = registrationRequired;
}
public class PlayerRegisteredCheck : IContextCheck<PlayerIsRegisteredAttribute>
{
private readonly IMediator _mediator;
public PlayerRegisteredCheck(IMediator mediator)
{
_mediator = mediator;
}
public async ValueTask<string?> ExecuteCheckAsync(PlayerIsRegisteredAttribute attribute, CommandContext context)
{
try
{
var player = await _mediator.Send(new GetPlayerByDiscordId(context.User.Id));
// logic to add player into cache here
return null;
}
catch (PlayerNotFoundException ex)
{
return "player is not registered";
}
}
}
should do it for registering checks then
you do need to register it with the extension, too
