티스토리 뷰

https://discordnet.dev/

 

Home | Discord.Net Documentation

 

discordnet.dev

 

Discord.Net을 사용하기 위한 패키지를 설치하는 방법은 다른 분들께서 많이 정리해주셔서 딱히 정리하지는 않으려고 합니다. 또한 튜토리얼 유튜브를 통해서도 알 수 있는데, 혹시 모르니 유튜브 채널 네임을 남겨드리겠습니다. 이 링크는 Discord.Net의 공식 디스코드에 들어가셔도 있습니다. 아래는 패키지 종류입니다.

Youtube Name : Crenston Customs - Coding

필요한 패키지 종류

 

먼저 Main의 코드는 다음과 같습니다. config.yml을 읽어오고, 사용할 클래스들을 Host.CreateDefaultBuilder을 통해 싱글톤으로 만든 후, 의존성을 주입합니다. 이렇게 되면, 각 클래스의 생성자에 필요한 인자들을 알아서 넘긴 후 실행합니다.

cofig의 경우, Key-Value 형태로 저장되기 때문에, 서론 #1의 config.yml 파일 형태를 참고해서 보시면 됩니다.

public static void Main(String[] args)
    {
        new Program().BotMain().GetAwaiter().GetResult();
    }
    
    public async Task BotMain()
    {
        // SetBasePath는 구성 정보의 기본 디렉터리 설정
        // config.yml 파일을 읽어오는 코드
        var config = new ConfigurationBuilder()
            .SetBasePath(AppContext.BaseDirectory)
            .AddYamlFile("config.yml")
            .Build();

        // 의존성 주입
        // Net Core 호스팅 환경 구성 및 애플리케이션 실행과 생명주기 관리 담당
        using IHost host = Host.CreateDefaultBuilder()
            .ConfigureServices((_, services) =>
            services
            .AddSingleton(config)
            // 디스코드 소켓을 싱글톤으로 관리
            .AddSingleton(x => new DiscordSocketClient(new DiscordSocketConfig
            {
                GatewayIntents = Discord.GatewayIntents.AllUnprivileged,
                AlwaysDownloadUsers = true,
            }))
            // SQL을 사용하기 위한 매니저
            .AddSingleton<SQLManager>()
            // InterationService 등록
            .AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordSocketClient>()))
            // Interation handler 등록
            .AddSingleton<InteractionHandler>())
            .Build();

        await RunAsync(host);
    }

 

다음은 RunAsync 입니다. 여기서는 방금 했던 host를 넘겨받은 후, 만들었던 싱글톤들의 객체를 가져와 초기화 및 등록작업을 하게 됩니다.여기서 Read에 넣는 람다함수의 경우, 두 가지로 나뉩니다.

Debug : Guilds들을 돌아 각 서버에 Command를 등록

Release : Global로 등록

public async Task RunAsync(IHost host)
    {
    	// GlobalHost에 등록된 싱글톤 스코프 가져오기.
        using IServiceScope serviceScope = host.Services.CreateScope();
        IServiceProvider provider = serviceScope.ServiceProvider;
		
        // 싱글톤에 등록된 소켓과 InterationService 가져오기
        var _client = provider.GetRequiredService<DiscordSocketClient>();
        var sCommands = provider.GetRequiredService<InteractionService>();
        
        // 읽어온 Yaml 파일에 대한 구성 정보를 가져오는 코드
        var config = provider.GetRequiredService<IConfigurationRoot>();

		// 가져온 싱글톤의 초기화 함수 실행
        await provider.GetRequiredService<SQLManager>().InitializeAsync();
        await provider.GetRequiredService<InteractionHandler>().InitializeAsync();
		
        // 로그 등록
        _client.Log += async (LogMessage msg) => { Console.WriteLine(msg.Message); await Task.CompletedTask; };
        sCommands.Log += async (LogMessage msg) => { Console.WriteLine(msg.Message); await Task.CompletedTask; };
		
        // Ready 상태, 즉 연결되었을 때 실행하는 함수(람다형식)
        _client.Ready += async () =>
        {
            await _client.SetGameAsync("Please Use / Command");

            if (IsDebug())
            { 
                foreach (var guild in _client.Guilds)
                {
                    ulong id = guild.Id;
                    await sCommands.RegisterCommandsToGuildAsync(id);
                }
            }
            else
            {
                await sCommands.RegisterCommandsGloballyAsync();
            }
        };
		
        // Discord 봇의 토큰값을 통해서 Discord에 로그인
        await _client.LoginAsync(TokenType.Bot, config["tokens:discord"]);
        
        // 디스코드 봇 실행
        await _client.StartAsync();

		// 종료되면 안되기 때문에 무한루프
        await Task.Delay(-1);
    }

// Debug인지, Release 모드인지 알려주는 함수
    static bool IsDebug()
    {
#if DEBUG
        return true;
#else
        return false;
#endif
    }

 

앞의 코드들은 Program.cs의 코드이며 다음은 InterationHandler.cs의 코드입니다.

변수들 같은 경우에는, 앞에서 의존성 주입을 통해 자동으로 생성이 되며 Init의 초기화를 통해 Command함수들을 등록하게 됩니다. 저기서 new SocketInterationContext이후 await을 통해 함수를 실행하게 되는데, 이때 InteractionModuleBase<SocketInteractionContext>라는 인터페이스를 상속받은 모듈의 함수를 실행하게 됩니다.

모듈과 Command 함수들은 다음의 #3에서 설명하겠습니다.

public class InteractionHandler
{
    private readonly DiscordSocketClient _client;
    private readonly InteractionService _commands;
    private readonly IServiceProvider _services;

    public InteractionHandler(DiscordSocketClient client, InteractionService commands, IServiceProvider services)
    {
        _client = client;
        _commands = commands;
        _services = services;
    }

    public async Task InitializeAsync()
    {
        await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);

        _client.InteractionCreated += HandleInteration;
    }

    private async Task HandleInteration(SocketInteraction arg)
    {
        try
        {
            var ctx = new SocketInteractionContext(_client, arg);
            await _commands.ExecuteCommandAsync(ctx, _services);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

 

 

전체코드

더보기

Program.cs

using Discord.Interactions;
using Discord.WebSocket;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Discord;
using Discord.Commands;
using System.Runtime.InteropServices;
using Discord.Net;
using Newtonsoft.Json;
using System.Threading.Tasks;

class Program
{
    public static void Main(String[] args)
    {
        new Program().BotMain().GetAwaiter().GetResult();
    }
    
    public async Task BotMain()
    {
        var config = new ConfigurationBuilder()
            .SetBasePath(AppContext.BaseDirectory)
            .AddYamlFile("config.yml")
            .Build();

        Util.GlobalHost = Host.CreateDefaultBuilder()
            .ConfigureServices((_, services) =>
            services
            .AddSingleton(config)
            .AddSingleton(x => new DiscordSocketClient(new DiscordSocketConfig
            {
                GatewayIntents = Discord.GatewayIntents.AllUnprivileged,
                AlwaysDownloadUsers = true,
            }))
            .AddSingleton<SQLManager>()
            .AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordSocketClient>()))
            .AddSingleton<InteractionHandler>())
            .Build();

        await RunAsync();
    }

    public async Task RunAsync()
    {
        using IServiceScope serviceScope = Util.GlobalHost.Services.CreateScope();
        IServiceProvider provider = serviceScope.ServiceProvider;

        var _client = provider.GetRequiredService<DiscordSocketClient>();
        var sCommands = provider.GetRequiredService<InteractionService>();
        var config = provider.GetRequiredService<IConfigurationRoot>();

        await provider.GetRequiredService<SQLManager>().InitializeAsync();

        await provider.GetRequiredService<InteractionHandler>().InitializeAsync();

        _client.Log += async (LogMessage msg) => { Console.WriteLine(msg.Message); await Task.CompletedTask; };
        sCommands.Log += async (LogMessage msg) => { Console.WriteLine(msg.Message); await Task.CompletedTask; };

        _client.Ready += async () =>
        {
            await _client.SetGameAsync("Please Use / Command");

            if (IsDebug())
            { 
                foreach (var guild in _client.Guilds)
                {
                    ulong id = guild.Id;
                    await sCommands.RegisterCommandsToGuildAsync(id);
                }
            }
            else
            {
                await sCommands.RegisterCommandsGloballyAsync();
            }
        };

        await _client.LoginAsync(TokenType.Bot, config["tokens:discord"]);
        await _client.StartAsync();

        Util.dayTimer = new DayTimer();
        Util.dayTimer.Start(() => { _ = Util.DoTimer(); });

        await Task.Delay(-1);
    }

    static bool IsDebug()
    {
#if DEBUG
        return true;
#else
        return false;
#endif
    }
}

 

InterationHandle.cs

using Discord;
using Discord.Interactions;
using Discord.WebSocket;
using System.Reflection;

public class InteractionHandler
{
    private readonly DiscordSocketClient _client;
    private readonly InteractionService _commands;
    private readonly IServiceProvider _services;

    public InteractionHandler(DiscordSocketClient client, InteractionService commands, IServiceProvider services)
    {
        _client = client;
        _commands = commands;
        _services = services;
    }

    public async Task InitializeAsync()
    {
        await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);

        _client.InteractionCreated += HandleInteration;
    }

    private async Task HandleInteration(SocketInteraction arg)
    {
        try
        {
            var ctx = new SocketInteractionContext(_client, arg);
            await _commands.ExecuteCommandAsync(ctx, _services);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

'개인적인 취미 > 디스코드 봇 만들기 With C#' 카테고리의 다른 글

SlashCommand Module 제작 #3  (0) 2023.06.12
서론 Discord.Net #1  (0) 2023.06.11
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함