Discord4J로 Java 기반 디스코드 봇 만들기
본 글은 Discord4J v2.10.1을 기준으로 작성합니다.
Discord4J는 수시로 업데이트 되는 라이브러리이기 때문에 상, 하위 버전에서는 작동하지 않는 코드가 있을 수 있습니다.
제 코드는 모든 면에서 완벽한 코드가 절때 아닙니다.
----------------------------------------
Discord 공식 API 가 변경되었고
이에 따라 Discord4J 도 3.0 버전으로 업데이트 되었습니다.
고로 이 글은 만료되었습니다.
Discord4J GitHub : https://github.com/Discord4J/Discord4J
----------------------------------------
디스코드는 메신저 기능과 음성채팅 기능을 가지고 있는 프로그램 입니다. 서버(그룹)을 생성하고 다른 사람들을 초대하거나 다른 서버에 들어가서 다른 사람들과 메세지나 미디어 파일을 주고받거나 음성채팅을 할 수 있습니다. 디스코드는 많은 편의기능 및 API를 제공하고 있는데, 봇 또한 디스코드에서 제공하는 기능입니다.
디스코드 봇은 디스코드의 API를 통해 유저와 똑같은 일을 할 수 있습니다(메세지 보내기, 음성채팅하기 등). 하지만 봇은 프로그램이기 때문에 사람이 일일히 답변하는 대신 들어오는 정보들을 사전에 만들어 둔 프로그램을 통해 자동으로 처리 혹은 응답 할 수 있게 해줍니다.
간단하게는 명령어처럼 '/시간' 이라고 보내면 지금 시간을 답해주는 기능을 만들수도 있고,
Discord4J의 Documentation(설명서)를 이해하실 수 있다면(혹은 관련 강좌글 코드를 싹 복붙한다면) 음성 채널에서 노래를 틀어주는 봇을 만들 수 도 있고,
여기에 추가로 다른 실무 프로그래밍을 해보신 분 이라면 매일 정해진 시간 마다 날씨를 알려줄 수 있는 봇을 만들 수 도 있습니다. 무엇을 만들 수 있는지는 자신의 코딩능력에 달렸죠.
1. 준비물
1. 기초적인 코딩, 영어 능력
대학교 컴퓨터공학과 1~2학년의 실무 프로그래밍 프로젝트(도서관 서적 관리 프로그램, 직원 혹은 학생 관리 프로그램 등)를 수행 가능 할 정도면 됩니다.
2. Java 코딩을 위한 이클립스 설치
https://www.eclipse.org
3. 디스코드 봇 등록 후 자신이 있는 서버에 초대하기
https://discordapp.com/developers
디스코드 사이트 로그인 후 Create an application 을 눌러줘서 새로운 봇을 만듭니다.
봇을 자신의 서버에 초대하려면 https://discordapp.com/oauth2/authorize?client_id=CLIENTID&scope=bot 링크에서 CLIENTID 를 자신의 봇 ID로 바꾼 링크로 접속하면 됩니다.
왼쪽 Settings에 Bot을 클릭하시면 BUILD-A-BOT 이라고 적힌 곳 오른쪽에 Add Bot을 클릭하여 봇으로 전환 후 TOKEN(토큰) 값을 준비해둡니다.
토큰값은 프로그램에서 봇으로 로그인 할 때 꼭 필요한 문자열입니다. 반대로 이 토큰값으로 누구나 자신의 봇에 접속할 수 있기 때문에 잘 지켜야 합니다.
있으면 좋은 준비물
1. 객체지향 언어에 대한 이해(Java 실력)
객체가 무엇인지, 절차지향 언어와의 차이점은 무엇인지 알고있으면 좋습니다.
2. 남이 짠 코드를 이해할 수 있을 정도의 코드 이해력(많은 실무경험?)
복붙만 하고 돌리는 것 보단 코드 한줄한줄 이해할 수 있다면 더욱 좋습니다.
3. Discord4J Documentation을 나름대로 해석할 수 있을 정도의 영어실력
https://jitpack.io/com/github/Discord4J/Discord4J/2.10.1/javadoc/
Discord4J 의 모든 메소드(기능)에 대한 설명이 적혀있는 웹 문서입니다. 이걸 이해하신다면 구현할 수 있는 기능이 무궁무진해집니다.
2. 이클립스 Java 프로젝트에 Discord4J 라이브러리 추가하기
봇을 만들 프로젝트를 하나 생성한 후 Discord4J 라이브러리를 추가해줍니다.
라이브러리를 추가하는 법은 다음 링크에 설명되어 있습니다.
https://github.com/Discord4J/Discord4J
Maven Project 나 수동으로 .jar을 프로젝트 속성에서 추가하는 쪽이 편합니다.
3. 기초 클레스 만들기
패키지에 메인 클레스를 만들고 밑의 코드를 붙여줍니다.
public class DiscordBot {
// 봇 정보 입니다. 자신의 입맛에 맞게 적어주세요.
// 봇의 토큰
private static final String BOT_TOKEN = "<봇 토큰>";
// 봇의 이름
public static final String BOT_NAME = "<봇 이름>";
// 봇의 Prefix
// Prefix 는 명령어를 구현할 때 문자열 제일 앞에 사용되는 문자 입니다.
// 예로 "^hi" 를 보냈을 때 봇이 "안녕" 이라고 답한다면 Prefix 는 "^" 입니다.
public static final String BOT_Prefix = "<봇 Prefix>";
private static IDiscordClient Client = null;
public static void main(String[] args) {
// Discord4J.LOGGER 는 Discord4J에서 지원하는 텍스트 로거입니다.
// System.out.print~(C언어의 printf("") 와 비슷한 기능) 은 한줄에 매개변수 문자열을 출력하지만
// Discord4J LOGGER 는 로그 발생 시간, 해당 코드가 실행된 클레스(객체)를 같이 출력해 줍니다.
Discord4J.LOGGER.info("봇 클라이언트 생성을 시도합니다.");
Client = createClient(BOT_TOKEN, true);
if (Client == null) {
// 오류 처리
Discord4J.LOGGER.error("클라이언트 생성에 실패하였습니다.");
return;
}
Dispatcher = Client.getDispatcher();
Dispatcher.registerListener(new InterfaceListener());
Discord4J.LOGGER.info("봇 클라이언트를 생성하였습니다.");
// 메인 함수 끝
}
// 디스코드 클라이언트를 생성하여 반환하는 함수
private static IDiscordClient createClient(String token, boolean login) {
ClientBuilder clientBuilder = new ClientBuilder();
clientBuilder.withToken(token);
try {
if (login) {
return clientBuilder.login();
} else {
return clientBuilder.build();
}
} catch (DiscordException e) { // 로그인 시도 중 발생한 예외 처리
e.printStackTrace();
return null;
}
}
}
빨간줄이 생기는 객체명들은 Import 자동 추가를 통해 해결합니다.
Ctrl + F11 로 코드를 실행하면 문제가 없다면 디스코드에서 자신의 봇이 온라인으로 변경될 것 입니다.
하지만 봇을 온라인으로 로그인 하는 것 밖에 없기 때문에 아무 기능이 없습니다.
코드 수정 후 다시 실행하기 전에 콘솔 디버그창에 ■을 눌러서 이전에 실행중인 봇을 종료시킨 후 다시 실행합니다.
4. 메세지를 인식할 수 있도록 하기
봇이 들어오는 메세지를 인식하려면 메세지가 들어왔을 때 발생하는 이벤트를 처리하는 함수를 만들어야 합니다.
Discord4J 에 보면 IListener 와 @EventSubscriber 를 이용하여 이벤트를 다루고 있습니다.
저는 IListener 객체를 이용하여 메세지를 다뤄보겠습니다.
패키지에 메세지 이벤트를 처리할 클레스를 만들고 밑의 코드를 붙여줍니다.
public class InterfaceListener implements IListener<MessageReceivedEvent> {
@Override
// MessageReceivedEvent(메세지 받음) 이벤트 가 실행될 시 작동되는 함수
public void handle(MessageReceivedEvent event) {
Discord4J.LOGGER.info("메세지 받음 : " + event.getMessage().getContent());
}
}
봇이 메세지를 받을 경우 handle(MessageReceivedEvent event) 함수 안에있는 내용이 실행됩니다.
이 코드의 경우에는 받은 메세지의 내용을 콘솔창에 뿌려주는 역할을 합니다.
메인 클레스로 돌아가서 디스패쳐 객체를 전역변수로 추가하는 코드를 추가합니다(main() 함수 바로 위에).
.
private static IDiscordClient Client = null;
private static EventDispatcher Dispatcher;
public static void main(String[] args) {
.
.
클라이언트가 정상적으로 생성되었는지 확인하는 코드 바로 아래에 디스패쳐를 설정 해주고 메세지를 처리하는 객체를 생성 및 등록시키는 코드를 추가합니다.
.
.
Discord4J.LOGGER.error("클라이언트 생성에 실패하였습니다.");
return;
}
// 디스패쳐 구하기
Dispatcher = Client.getDispatcher();
// 이벤트를 처리하는 객체를 생성하고 디스패쳐에 연동시키기
Dispatcher.registerListener(new InterfaceListener());
Discord4J.LOGGER.info("봇 클라이언트를 생성하였습니다.");
// 메인 함수 끝
}
다시 Ctrl + F11 로 코드를 실행한 후 봇이 있는 채팅방에서 말을 하면 콘솔창에서 들어온 메세지를 확인할 수 있습니다.
만약 봇이 메세지를 못읽는다면 디스코드 채팅방에 봇이 메세지 읽기 권한을 가지고 있나 확인해주세요.
5. 메세지 보내기
메세지를 듣는 기능만 필요할 경우도 있으나 답장까지 보낼 수 있다면 피드백이 가능해져서 더욱 좋겠지요.
// 메세지를 보내는 함수
public static void sendMessage(IChannel channel, String message) {
RequestBuffer.request(() -> {
try {
channel.sendMessage(message);
} catch (DiscordException e) {
Discord4J.LOGGER.error("메세지를 보내지 못했습니다.");
e.printStackTrace();
}
});
}
이 함수 코드를 새로 클레스를 만든 후 추가하거나 메인 클레스 밑쪽에 추가합니다. 전 메인 클레스 속에 추가함.
이 함수는 매개변수로 받은 채팅채널에 2번째 매개변수에 있는 문자열을 전송하는 함수 입니다.
메세지 이벤트를 처리하는 클레스 속 handle 다음과 같은 코드를 추가합니다.
.
.
public void handle(MessageReceivedEvent event) {
Discord4J.LOGGER.info("메세지 받음 : " + event.getMessage().getContent());
DiscordBot.sendMessage(event.getChannel(), "메세지 받음"); // 이 코드를 추가
}
}
메세지를 처리하는 함수에 코드를 한줄 추가합니다.
이 때 DiscordBot.sendMessage 는 DiscordBot 클레스에 public static 으로 선언된 sendMessage 함수를 가르키는 겁니다.
따라서 sendMessage 가 어느 클레스에 있던, private 또는 non-static 으로 선언되어 있다면, 메세지 이벤트를 처리하는 클레스 속 코드가 메세지를 보내는 함수에 접근하는 것이 불가능 하기 때문에 주의해야 합니다.
코드가 정상적으로 실행된다면 봇이 답장을 하시는 것을 볼 수 있습니다.
6. 명령어(커멘드) 구현하기
사실 메세지가 오는 족족 답장하는 기능은 필요가 없습니다.
명령어 구현을 통해 봇이 받아들이는 명령어 별로 정해진 기능을 구현하면 좋습니다.
메세지 이벤트를 처리하는 클레스의 handle 함수 코드를 다음과 같이 수정해줍니다.
public void handle(MessageReceivedEvent event) {
// 문자열 변수 msg 에 받은 메세지의 내용을 저장합니다.
String msg = event.getMessage().getContent();
// 만약 받은 문자열의 시작이 봇 Prefix 인 경우(받은 문자열이 명령어일 경우)
if(msg.startsWith(DiscordBot.BOT_Prefix)) {
// 받은 문자열속 공백들을 기준으로 쪼개서 새로운 문자열 배열 args 를 만듭니다.
String[] args = msg.split("\\s");
// 첫번째 문자열 배열 속에 담긴 문자열에서 제일 앞 부분인 봇 Prefix를 지웁니다.
// 제 경우의 예시로는 Prefix : "^", ^hi -> hi
args[0] = args[0].substring(DiscordBot.BOT_Prefix.length());
// 배열의 총 길이가 1 일 경우
if(args.length == 1) {
// 첫번째 배열 속 문자열이 "hi" 일 경우
if(args[0].equals("hi")) {
// 메세지를 보냅니다.
DiscordBot.sendMessage(event.getChannel(), "안녕");
}
}
}
}
BOT_Prefix + "hi" 라는 문자열을 받으면 그 채팅채널에 "안녕" 이라고 답장을 보내는 코드 입니다.
여기서 BOT_Prefix 또한 DiscordBot 객체에서 가져오는 값 이기 때문에 이 또한 private 로 선언되면 안됩니다.
봇 실행 후 문제가 없다면 Prefix + "hi" 의 문자열을 채팅에 보내시면 봇이 "안녕" 이라고 답합니다. 저 같은 경우는 Prefix 가 "^" 입니다.
-
이로써 간단한 명령어를 받는 봇을 구현하는 법을 알아봤습니다.
이것을 배이스로, 공식 깃허브나 도큐멘테이션, 다른 튜토리얼 강좌를 통해
자신이 만들고 싶은 기능이나 더 복잡한 기능을 가진 봇을 만들 수 있습니다.
-
○ 참고 URL
공식 GitHub 사이트(영어)
- https://github.com/Discord4J/Discord4J
Discord4J 봇 튜토리얼 강좌(영어)
- https://discord4j.readthedocs.io/en/latest/
Discord4J v2.10.1 도큐멘테이션(영어)
- https://jitpack.io/com/github/Discord4J/Discord4J/2.10.1/javadoc/