개인 자료란 (JE)

  서버 커뮤니티

Profile Kobins 대표칭호 없음

Kobins 7e61baba5cec465d89e9b4c5615ae13e

Profile

강좌 자바 에디션(JE) 플러그인 개발

[마시자] 마인크래프트로 시작하는 Java 2강 - 이벤트(Event) 등록

2020.03.07 조회 수 2112 추천 수 4
분야 플러그인 
장르 개발자 툴 
게임버전 모든버전 
API 스피곳, 페이퍼 

1776ced7247c675b457e79b884389828.png

마인크래프트로 시작하는 Java 2강 목차

이벤트 등록

여러가지 행동을 감지하자

이전에는 조금 이론적인 내용으로 진행했었습니다. 하지만 이전 강의의 내용을 자세히 알 필요는 없고, 사실 지금부터 강좌가 진짜로 플러그인을 처음 배우는 분들에게 의미가 있을 것입니다.

저번 강의에서 이야기했듯이, 이벤트는 플러그인 개발의 핵심이며, 사실상 마인크래프트에서 서버가 인식할 수 있는 플레이어나 엔티티, 블럭, 자연 등에 의한 모든 동작들을 감지하고 그것을 가공할 수 있습니다.

지금부터 이벤트에 대해 하나씩 알아가봅시다.

이벤트 기본 설정

a0cf7c5ce87544890aef70ebf04a7043.png

저번에는 단순하게 서버가 켜질 때(플러그인이 활성화될 때) 메세지를 띄우는 것에 그쳤습니다. 참 단순무식한 플러그인이죠?

이벤트를 사용하기 위해서는 한 가지 과정이 필요합니다. 바로 플러그인 관리자(PluginManager)리스너(Listener, 수신자) 클래스를 등록해야 합니다.

리스너 클래스는 인터페이스(클래스와 비슷한 개념) Listenerimplement(상속과 비슷한 개념)한 클래스로
말 그대로 '이 클래스는 이벤트를 받는 클래스다' 라는 것을 의미하는 클래스입니다.

- 아직 implement라는 개념은 이해할 필요 없습니다.

우리는 단순하게 리스너 클래스로 EventManager라는 클래스를 만들어 볼 겁니다. 이름 참 직관적이죠?

4fa37fe3b88bd53ca9c06f3d79c064b8.png

새로운 클래스를 하나 만들어 줍시다!
dcd0953553eff4de84d19c96ac971889.png

클래스 EventManager 생성!

7cc17ee2f7cbd191b496ca96e5921fbb.png

메인 클래스 만들 때랑 똑같네요. 그죠?

사실 별도로 EventManager를 만들 필요 없이 바로 Main 클래스에 Listener를 박아도 됩니다만,
여기서는 클래스를 새로 만들어 기능에 따라 분화하는 개념을 잡기 위해 새로 클래스를 만들었습니다.

6d923cb31d1a03ca518d7f0f612b132d.png

메인 클래스에 JavaPlugin 썼듯이 여기서는 implements Listener 를 뒤에 붙여줍시다!

이를 통해 EventManager라는 클래스는 Listener 인터페이스를 implement 합니다! (아직 이해 안해도 됨)

이제 저 안에 내용을 만들어 봅시다. 무슨 내용으로 할까요..? 가장 쉬운 플레이어가 서버를 접속할 때로 해보겠습니다.


Listener 클래스에 이벤트를 받기 위해서는 이벤트 클래스를 인자로 받는 @EventHandler가 붙여진 public 메소드가 필요합니다. 그리고 그 형태는 다음과 같습니다.

f10b854dfece3a28dcf7bfdcc36401f6.png

@EventHandler
public void onJoin(PlayerJoinEvent e){

}

@EventHandler

public void <메소드 이름>(<이벤트 클래스> e){ ... }

와 같은 형태로 작성합니다.

@EventHandler메소드 바로 위에 붙어있어야 하며, 메소드 이름자유롭게 원하는 대로(필자는 onJoin과 같은 형태로 작성함), 이벤트 클래스수신하기를 원하는 Event 클래스를 적어줍니다.

아직 자세히 설명하지 않았지만, PlayerJoinEvent ePlayerJoinEvent라는 클래스(타입)의 매개 변수를 e라는 이름으로 받게 되며, 이벤트가 발생할 때 이벤트에 대해 가공하거나 여러 정보를 받아오려면 e에 대해 참조(Reference)하면 됩니다.

말이 어려운데, 직접 써가면서 익혀봅시다.

1fb9f51d5df62024395daefc0a494495.png

우린 이 메세지를 수정하고 싶습니다. 아주 멋드러진 친구로!

그리고 저번 강좌에서 말했다 시피, 이벤트는 특정 행동이 발생하는 것 뿐만 아니라 해당 이벤트에 관련된 행동에 대해 수정할 수 있다고 배웠습니다.

대충 감을 잡으셨겠지만, PlayerJoinEvent에는 플레이어의 메세지를 수정할 수 있는 메소드가 제공됩니다. 따라와 볼까요?

91b02347bf6907f45d92882adc623dec.png

아까 말했듯, 이벤트에 대해 가공하거나 여러 정보를 받아오려면 e에 대해 참조하면 된다 했으니, 일단 e를 적어봅시다.
- 저기 있는 e는 매개변수의 이름입니다. 즉 여러분들 마음대로 바꾸어 event, joinEvent와 같이 사용할 수 있으나 평범하게 EventHandler를 통해 받아오는 경우에서는 e 또는 event를 주로 사용합니다. 개인 취향 차이.

그리고, 어떤 클래스(모든 이벤트는 클래스입니다!)에 대해 참조(Reference)하려면 저 e 뒤에 . (점)을 붙이시면 됩니다!

105216a821e72352d49ca43867478adc.png

와우! 점만 붙여도 알아서 자동완성까지 해주네요.

대충 우리가 하려는 걸 감을 잡으신 분들은 알겠지만, 우리가 필요한 것은 setJoinMessage(String joinMessage) 라는 메소드가 필요합니다.

b9cd2d4c4ef9853a9066874eb58520a8.png

자동완성으로 써 주시고, 이제 커서가 저 노란색 괄호 사이로 들어가 있을텐데, 우리가 원하는 메세지를 적어주면 됩니다.

저번 강좌에서 슬쩍 넘어간 부분이 있는데, 큰 따옴표 두 개 사이의 모든 문자는 문자열(String)을 의미합니다.

b81107c2f0d38d3becd9adb4d1385595.png

이렇게 쓰면 안 되고,

e01eb3602125560d68d666b93dbd685b.png

이렇게! 큰 따옴표 안에 넣어주면 저렇게 초록색으로 씌워지게 됩니다.

근데, 우린 저렇게 인사만 하면 안되지요? 어떤 플레이어가 들어왔는지 알고 싶은데 ... 음... 어떻게 해야할까요?

잠시, 다시 e에 대해서 참조해봅시다.

092d2306a35958fddeafd605a37ae5fd.png

아하! 꽤 그럴듯한 친구가 눈에 띄네요. 저 친구를 한번 봅시다.

261b573ae6aae396c25c5a32f8649431.png

음.. 기능이 꽤 많네요?

잠깐, 방금 보았던 getPlayer()라는 메소드는 뭐하는 친구일까요?

바로 이벤트 내에서 접속한 플레이어(Player) 객체를 얻어오는 메소드입니다!

플레이어 객체는 실제로 플레이어에 관련된 여러가지 정보와 기능들을 담고 있으며, 앞으로 여러 가지 기능들을 만들 때 세상 많이 만질 객체 중 하나입니다.

그리고, 눈치 채신 분들도 있겠지만 모든 메소드의 괄호 안에 무언가 존재하지 않아도 됩니다.

setJoinMessage(String joinMessage)와 같은 메소드는 String 타입의 매개 변수를 받고 있지만,

getPlayer()와 같은 메소드는 매개 변수를 받지 않습니다. 오히려 Player 객체를 우리가 얻어오지요!

뭔 소린지 모르겠다면, 다음 강의에서 설명할게요!

아무튼, 저기서 우리는 플레이어의 이름을 가져오고 싶으니 ... 대충 name 정도만 써 볼까요?

32e8fb65244b51fc2439fd9177574b63.png

우리가 원하는 친구가 바로 위에 있네요! getName()을 자동완성 해 줍시다.

cf5b5ac29be65d6d27901550074ec7c9.png

음 ... 근데 이런다고 해서 안녕? 이라는 문자 뒤에 플레이어의 이름이 알아서 붙여지지는 않을테고...

그러므로 우리는 문자열 뒤에 이름을 붙여줄겁니다.

18c1e54d344d703a7d6fd7b117956d67.png

바로 이렇게!

아직 우리는 문자열(String)도, 메소드(Method)도, 변수(Variable)의 타입(primitive type ... )도, 연산자(Operator)도 배우지 않았지만, 대충 무슨 느낌인지는 잡히실거에요.

바로 안녕 뒤에 플레이어 이름이 온다는 사실은 어떤 원리인지는 모르겠지만 감은 오시죠?

그렇다면, 이제 이벤트 클래스를 등록하러 가 봅시다!

예? 끝난거 아니었냐구요? 아직 한 과정이 남아있지요!

1d41452f4adbc027e17ffb5478ae1a61.png

메인 클래스로 되돌아가봅시다.

그리고 우리는, 위에서 말했던 플러그인 관리자에게 아까 만든 리스너 클래스인 EventManager를 등록시킬 거에요.

43bb54c05243dba6118e0ac11ccc3d14.png

잠시 Bukkit이라는 이름을 써 봅시다.

- 메인 클래스는 JavaPlugin을 상속한 클래스이기 때문에 getServer()를 사용해도 됩니다. 어차피 같은 동작임

0790b01862a25608f60e9d050d0e6f2e.png

그리고, 아까 우리가 Player 객체를 얻어올 때 했던 것 처럼, getPluginManager()를 통해 PluginManager 객체를 얻어옵시다!

1e6a96874f80b8db473bb903ec349283.png

좋아요! 바로 이거네요. 아까 말했던 Listener를 매개 변수로 받는 클래스!

ab6998e63fc5743eccf3bd97208d67af.png

어... 근데 이렇게 적으면 싫어하나봐요? Bukkit은 별로 문제를 삼지 않던데?

저런, 사실 Bukkit에 참조하는 것은 우리가 여태 해 왔던 객체에 대한 참조와는 살짝 다른 친구입니다.

즉, 우리는 객체지향 내용 중 하나인 생성자(Constructor)를 통해 등록해야 합니다...

써보면서 느끼는건데 기초 강좌에 객체지향적 내용이 들어가는게 너무 많네요... 언제 다 설명하지?

2191cc5cf00335a1a7f00db87ec30515.png

바로 이렇게!

그리고 뒤에 plugin 부분은 this를 써 주시면 됩니다.

c464d6766dc1b4e796db88d3f4af0b5c.png

이제 서버가 켜질 때 서버의 플러그인 관리자가 우리의 EventManager 클래스를 이벤트 수신 클래스로 등록하여, 매번 플레이어가 들어올 때 마다 안녕? <플레이어 이름>이라는 메세지를 띄워주겠죠?

605dd7ac9b6e8e7f765ff3808a5e5923.png

빌드!

e7c3ace83836d622aadf59a8c6cbee88.png

오픈!

540b701c2500735b10643574502d908d.png

과연?

4fd0978470ab8d7b88babcce0b2995ed.png

와우!


좋아요. 이제 우리는

  1.  Listener 클래스를 만들고
  2. 그 클래스에 @EventHandler가 붙은 Event 클래스를 인자로 받는 public 메소드를 만들고
  3. 그 이벤트를 수정하고
  4. 메인 클래스에서 그 Listener 클래스를 PluginManager에 등록

까지 했네요!

와우!


목차




10개의 댓글

ZoniIC645
2020.03.07

좋은 강의 감사합니다

초스터
2020.03.07

너무나도 멋진 강좌입니다. 감사해요 :D

참고로 우수강좌란에 바로 글을 쓰실 수 있으니 참고해주시면 감사하겠습니다!

sheep
2020.03.16

public void onEnable() {

logger.info("sheep 플러그인 활성화");

Bukkit.getPluginManager().registerEvents(listener: new EventManager(),plugin: this)

}

여기서 listener하고 plugin에서 Cannot resolve symbol 'listener' 이런 식의 오류가 뜨는데 뭐가 문제일까요

Kobins
2020.03.17
@sheep

윽! 강좌 사진에 있는 listener: 하고 plugin: 이 두개는 IntelliJ IDEA에서 지원하는 매개변수 이름 표시 기능입니다! 따라 안 쓰셔도 돼요!

public void onEnable() {
    logger.info("sheep 플러그인 활성화");
    Bukkit.getPluginManager().registerEvents(new EventManager(), this)
}

이 상태로 쓰시면 됩니다!!!

sheep
2020.03.19
@Kobins

아하 그렇군요

좋은 강좌 좋은 답변 감사합니다!!

SAHYUN
2020.03.28

좋은강좌 잘 보고 있습니다!

감사해요

아레나17506310
2021.05.22

e.setJoinMessage 가운데에 줄이 그어진 상대로 나오고 빌드한뒤에 적용했을때 참여문구가 안바뀌는데 뭐가 문제일까요?

아이유참좋다
2021.10.19

package main;

 

import org.bukkit.entity.Player;

import org.bukkit.event.EventHandler;

import org.bukkit.event.player.PlayerJoinEvent;

 

import java.net.http.WebSocket;

 

public class EventManager implements WebSocket.Listener {

 

@EventHandler

public void onJoin(PlayerJoinEvent e){

e.setJoinMessage("환영합니다."+e.getPlayer().getName());

}

 

}

 

 

setJoinMessage에 가로로 선이 그어져 있는데 왜 그런건가요?

IRONBLOCK
2023.08.21
@아이유참좋다

java.net.http를 임포트하셨네요 org.bukkit.event.Listener를 임포트해보세요!

뉴스 및 창작물
/files/thumbnails/520/751/003/262x150.crop.jpg?20240328020349

레드스톤

마인크래프트 노트블록으로 만든 『 Bling‐Bang‐Bang‐Born 』 1

Sonttukk

2024-03-23

1

/files/thumbnails/467/742/003/262x150.crop.jpg?20240311163123

레드스톤

[노트블럭커버] MILGRAM -ミルグラム(밀그램)- / 아마네 「숙청 행진」 제 2심 2

리비온

2024-03-11

0

/files/thumbnails/846/741/003/262x150.crop.jpg?20240310221214

레드스톤

워든 vs 라마 200마리 1

GlassesFilm

2024-03-10

0

/files/thumbnails/542/739/003/262x150.crop.jpg?20240309070457

레드스톤

[고인의 명복을 빕니다][노트블럭]드래곤볼 GT 오프닝 - 점점 마음이 끌려

리비온

2024-03-09

0

/files/thumbnails/326/738/003/262x150.crop.jpg?20240328020414

레드스톤

마인크래프트 노트블록으로 만든 『 Build Our Machine 』

Sonttukk

2024-03-07

0

/files/thumbnails/952/735/003/262x150.crop.jpg?20240303230423

소식

복잡한 설치 없이 마크 애드온을 즐겨보세요! 새로운 블록, 몹, 조합법 등!

도라

2024-03-03

0

/files/thumbnails/212/735/003/262x150.crop.jpg?20240303113438

레드스톤

성장속도 실험

GlassesFilm

2024-03-03

3