개인 자료란 (JE)

  서버 커뮤니티

Profile 난아무것도몰라요 대표칭호 없음
Profile

플러그인 제작

마인크래프트 플러그인 만들기 2강 - 커맨드(사실은 TabCompleter...)

2020.09.28 조회 수 1882 추천 수 0

안녕하세요 난 아무것도 몰라요라고 합니다.

벌써 두번째 강되네요.

원래는 오늘 3강이 올라왔어야 하는데 개인적 사정에 의해 1주일 정도 미뤄졌습니다.... 


오늘은 한번 커맨드에 관하여 알아봅시다. 

커맨드 또한 널리고 널린 강좌중 하나죠. 하지만 이번에는 TabCompleter도 함께 알아볼겁니다. (안그러면 삭제처ㄹ...읍읍)


자 그럼 시작하기 앞서 패키지를 우클릭 > New > Java Class를 눌러 새로운 클래스를 만들어 줍시다.

클래스 이름은 Commands로 해주고(클래스 이름은 자기 맘대로 지어도 상관 없습니다)

그뒤 클래스의 이름옆에 implements TabExecutor을 적어줍시다.  

public class Commands implements TabExecutor {}

이렇게요.

그럼 이부분이 빨간줄이 그어질 겁니다. 오류가 났다는 거에요. TabExecutor의 매소드들을 구현해야 한다는 거죠. 

그럼 구현해 봅시다. 오류난 부분에 마우스를 올리고 Alt + Enter을 누릅니다. 그뒤 Implement methods > Ok를 눌러 구현을 해주세요.

그럼 매소드 두개가 쫘란! 하면서 생겨났을 겁니다. 

public class Commands implements TabExecutor {

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        return false;
    }

    @Override
    public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
        return null;
    }
}

이렇게요. 커맨드만들기는 곂치는 부분이 많기에 생략하겠습니다. 

커맨드에 관하여 알고싶으시다면 다른 강좌를 참고해 주세요.

그럼 onCommand는 재껴두고 onTabComplete를 알아봅시다.


일단 command/test이면 args[0]의 추천으로 hihello가 뜨게 해봅시다.

일일이 설명하면 복잡하기에 미리 코드를 보여주고 그 코드를 해석하는 식으로 해보겠습니다

@Override
public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
    if(command.getName().equals("test")) {
        if(args.length == 1) {
            return Arrays.asList("hi", "hello");
        }
    }
    return null;
}

해석을 해보겠습니다.

만일 command/test이고 현제 명령어를 칠려고 하는 부분이 args[0]이라면 List에 담긴 문자열을 sender에게 추천으로 보여주어라. 이정도로 해석할 수 있겠네요. 


그럼 이번엔 args[0]hi이고 command /test이면 args[1]의 추천으로 모든 플레이어의 이름을 띄워봅시다

@Override
public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
    if(command.getName().equals("test")) {
        if(args.length == 1) {
            return Arrays.asList("hi", "hello");
        }else if(args.length == 2) {
            if(args[0].equals("hi")) {
                List playerList = new ArrayList<>();
                Bukkit.getOnlinePlayers().forEach(p -> playerList.add(p.getName()));
                return playerList;
            }
        }
    }
    return null;
}

업그레이드된 onTabComplete코드입니다!

해석에 들어가자면, command/testargs의 길이가 2이고 args[0]hiplayerList라는 이름을 가진 새로운 List을 생성하고 버킷에서 모든 플레이어를 가지고 와서 그 모든 플레이어를  playerList에 담고 return한다.(args[1]의 추천으로 띄운다) 정도가 될것같네요.

참고로 forEach(p -> playerList.add(p.getName())) 의 경우 람다식으로 logdev님이 다루어 주실거에요. 


그럼 테스트를 해보죠.

잠깐! 그전에 일단 커맨드 등록을 해줍시다.

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    if (command.getName().equals("test")) {
        if (sender instanceof Player) {
            if (args.length == 1) { //ArrayIndexOutOfBoundsException이 발생하는걸 막기 위해
                if (args[0].equals("hello")) { //자신이 있는 월드의 사람들에게 인사하는 명령어
                    Player p = (Player) sender;
                    p.getWorld().getPlayers().forEach(player -> player.sendMessage("§e§l" + p.getName() + "§r님이 인사합니다! 와!"));
                } else {
                    sender.sendMessage("§c알 수 없는 명령어 입니다");
                }
            } else if (args.length == 2) {
                if (args[0].equals("hi")) { //특정플레이어에게 인사하는 커맨드
                    try { //오류(예외)를 막기위한 try{}catch(){} 블럭
                        Player p = (Player) sender;
                        Player target = Bukkit.getPlayer(args[1]);
                        target.sendMessage("§6[§e" + p.getName() + "§6] §f: 안녕하세요");
                    } catch (NullPointerException ex) { //서버에 그런플레이어가 없을때 발생하는 오류
                        sender.sendMessage("§c알 수 없는 플레이어 입니다");
                    }
                } else {
                    sender.sendMessage("§c알 수 없는 명령어 입니다");
                }
            } else {
                sender.sendMessage("§c명령어가 너무 짧습니다");
            }
        } else {
            sender.sendMessage("콘솔에선 사용할 수 없는 명령어 입니다. 인게임 내에서 사용해 주세요");
        }
    }
    return false;
}

(위에는 예시 커맨드)

getCommand("test").setExecutor(new Commands()); //Executor을 등록하는 매소드
getCommand("test").setTabCompleter(new Commands()); //TabCompleter을 등록하는 매소드

onEable안에 이런 매소드 넣어서 등록해 주고...

commands:
  test:
    description: test

이렇게 plugin.yml에도 커맨드 등록도 해주고...


b7812fe850cc664b4cf87b4dffae66b4.png

이렇게 잘 로드되는지 확인도 해보고... 그러면

인게임 내에서 테스트를 해보면!

6f76f091f4f7ccc92348387955962168.png

짜잔! 실행이 잘되는 모습입니다


34b85251bbbdcfe1b30dd4c876dbec48.png

3e49d275108e5115cde5513318b62996.png


오류메시지도 잘 뜨는지 살펴보고


394c55c376508687a49332cd224170eb.png

9a08b7118e27979dd2d6a15e594f2881.png

실행도 잘되는지 확인을 하시면 됩니다!


후 벌써 4200자네요 (코드부분이 많이 차지함)

그럼 다음 강좌는 커맨드 응용편 입니다!

 혹시 원하시는 강좌가 있으시다면 댓글로 남겨주세요. 그럼 안녕히...

3개의 댓글

Ru_Nan
2020.10.29

if로 명령어의 성공 실패는 어떻게 구현해야 합니까

@Ru_Nan

오랜만에 왔네요

명령어의 성공 실패 라는것이 무엇인가요?

lhh2020
2020.11.15

잘 봤습니다

뉴스 및 창작물
/files/thumbnails/477/930/003/262x150.crop.jpg?20241201030912

레드스톤

뉴진스 - Super Shy | 마크 노트블럭 커버

노트블럭전문가

2024-12-01

0

/files/thumbnails/483/916/003/262x150.crop.jpg?20241127115329

레드스톤

[노트블럭 커버] 뉴진스 - ETA 3

노트블럭전문가

2024-11-27

1

/files/thumbnails/150/925/003/262x150.crop.jpg?20241123005717

건축

응답하라 1988 ? 1

팀뉴일리시

2024-11-23

5

/files/thumbnails/761/908/003/262x150.crop.jpg?20241025153749

건축

서울 숭례문(崇禮門) 6

KHC

2024-10-25

2

/files/thumbnails/578/899/003/262x150.crop.jpg?20241010142350

건축

경주 월정교 1

KHC

2024-10-10

2