개인 자료란 (JE)

  서버 커뮤니티

Profile 팬달03 대표칭호 없음
Profile

질문하기 플러그인

[플러그인 질문] 플레이어의 특정 게임모드를 감지

2024.07.27 조회 수 104 추천 수 0
이해도 입문자 
게임버전 (JE) 관련없음 
게임버전 (BE) 관련없음 

플러그인을 이용하여 크리에이티브인 플레이어를 제외한, 온라인 플레이어들에게 양털을 지급하려 합니다.


온라인 플레이어들에게 아이템을 지급하는 코드까지 짠 상태이고, 게임모드가 크리에이티브인 플레이어만 제외하는 방법을 알고 싶습니다.


아래는 코드입니다.

package me.pandal.randomwool;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.ArrayList;
import java.util.List;

import static org.bukkit.Material.*;

public final class Randomwool extends JavaPlugin implements Listener, CommandExecutor {

    public static void randomwool(String[] args) {
        List<String> wools = new ArrayList<String>();

        wools.add("red_wool");
        wools.add("orange_wool");
        wools.add("yellow_wool");
        wools.add("green_wool");
        wools.add("blue_wool");

        System.out.println("red_woll, orange_wool, yellow_wool, green_wool, blue_wool:");
        for (String wool : wools) {
            System.out.println(wool);
        }

        int size = wools.size();
        System.out.println("5:" + size);
    }

    public void onEnable() {
        getLogger().info("랜덤양털 정상작동");
        getServer().getPluginManager().registerEvents(this, this);
        this.getCommand("랜덤게임").setExecutor(this);
    }

    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        Player player = (Player) sender;
        ItemStack red_wool = new ItemStack(Material.RED_WOOL);
        ItemStack orange_wool = new ItemStack(ORANGE_WOOL);
        ItemStack yellow_wool = new ItemStack(YELLOW_WOOL);
        ItemStack green_wool = new ItemStack(GREEN_WOOL);
        ItemStack blue_wool = new ItemStack(BLUE_WOOL);

        blue_wool.setAmount(8);

        for (Player all : Bukkit.getOnlinePlayers())

            if (cmd.getName().equalsIgnoreCase("랜덤게임")) {
                if (args.length == 0) {
                    player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                } else if (args[0].equalsIgnoreCase("random")) {
                    int random = (int) (Math.random() * 5);

                    switch (random) {
                        case 0:
                            all.getInventory().addItem(red_wool);
                            player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                            break;
                        case 1:
                            all.getInventory().addItem(orange_wool);
                            player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                            break;
                        case 2:
                            all.getInventory().addItem(yellow_wool);
                            player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                            break;
                        case 3:
                            all.getInventory().addItem(green_wool);
                            player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                            break;
                        default:
                            all.sendMessage(String.valueOf(ChatColor.RED) + "WARNING 오류 발생!!");
                    }
                }
            }
        return false;
    }

}

26개의 댓글

qsef1256
2024.07.27

player.getGameMode() 를 사용하시면 됩니다.

팬달03
2024.07.27
@qsef1256

도와주셔서 정말 감사드립니다만... 위 코드 중 어디에 넣어야 하는지 알 수 있을까요?
이 코드를 어디에 넣어봐도 그저 case 하나가 더 추가되었을 뿐 제가 원하는 효과를 얻지 못하였습니다.

저는 크리에이티브의 플레이어는 양털을 아예 받지 않기를 원합니다.

            if (cmd.getName().equalsIgnoreCase("랜덤게임")) {
                if (args.length == 0) {
                } else if (args[0].equalsIgnoreCase("random")) {
                    if (player.getGameMode() == GameMode.SURVIVAL) {
                        int random = (int) (Math.random() * 4);

                        switch (random) {
                            case 0:
                                all.getInventory().addItem(red_wool);
                                player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                                break;
                            case 1:
                                all.getInventory().addItem(orange_wool);
                                player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                                break;
                            case 2:
                                all.getInventory().addItem(yellow_wool);
                                player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                                break;
                            case 3:
                                all.getInventory().addItem(green_wool);
                                player.sendMessage(ChatColor.GREEN + "양털 색 확인!!");
                                break;
                        }
                    } else if (player.getGameMode() == GameMode.CREATIVE) {
                        player.sendMessage(ChatColor.AQUA + "당신은 관리자입니다.");
                    }
                }
            }
        return false;
    }
}
qsef1256
2024.07.28
@팬달03

문제는 지금 올려주신 코드에 있지 않습니다, for (Player all : Bukkit.getOnlinePlayers()), 즉 all을 대상으로 반복을 하셨으니 체크도 all을 대상으로 하셔야 합니다. 여기 player는 명령어를 보낸 사람, 즉 sender니까 그걸 체크하시면 안됩니다.

qsef1256
2024.07.28
@팬달03

이 문제의 원인은 변수 이름을 잘못 지은 것에 있습니다. sender를 지금 반복을 돌리는 all와 착각해서 벌어진 문제죠. 이름을 잘 짓는데 거의 절반의 유지보수 비용 절감 효과가 있다는 것은 빈말이 아닙니다. player 대신 sender를 사용하셔야 했고 (파라미터와 겹치는 경우 그냥 sender를 commandSender로 바꾸셔도 될 것 같네요), 반복을 돌리는 all은 player 또는 nowPlayer 등으로 바꾸시는 게 좋습니다.

qsef1256
2024.07.28
@팬달03

그리고 다른 문제도 있는데, 지금 cmd.getName().equalsIgnoreCase를 반복문 안에서 하고 있으시네요, 이 체크는 한번만 해도 됩니다. 근데 지금 불필요하게 플레이어 수 만큼 체크를 하게 만들고 있는 것 같네요.

qsef1256
2024.07.28
@팬달03

또한 자바에서 변수 이름을 짓는 컨벤션, 즉 표준은 camelCase 입니다. snake_case는 id 문자열 같은 거로는 자주 사용하지만 자바 코드 자체에서는 거의 안 씁니다.

qsef1256
2024.07.28
@팬달03

또 지금 "양털 색 확인!"을 sender에게 계속 보내고 있으신데 이걸로 채팅창이 도배가 될 껍니다, 의도한 동작인지 궁금하네요.

qsef1256
2024.07.28
@팬달03

그리고 switch 문에 있는 반복 코드는 장기적으로 정리 되어야 합니다. 메서드 화 하거나 비슷한 종류의 리팩토링 으로 해결 가능할 것으로 보입니다.

qsef1256
2024.07.28
@팬달03

사실 지금 JavaPlugin이 Domain의 역할도 하고, Listener의 역할도 하고, CommandExecutor의 역할도 하는 건 좋지 못합니다, 전부 다른 클래스로 쪼개져야 하는 부분입니다. 사실 Listener나 CommandExecutor는 저는 라이브러리를 써서 간단하게 쓰고 있습니다, 관련해서 찾아보는 게 생산성에 더 도움이 될 것으로 생각하고요.

qsef1256
2024.07.28
@팬달03

randomWool 메서드는 아예 사용이 안된 것 같아요, 필요 없는 코드라면 바로바로 지우는 게 좋습니다.

qsef1256
2024.07.28
@팬달03

또 지금 if 문으로 들여쓰기가 너무 중첩이 된 상태인데, Guard Clause 방법을 써서 조건 체크하고 안 맞으면 return을 하는 식으로 짜면 중첩을 좀 줄일 수 있습니다. 그러면 가독성과 유지보수성에 도움이 됩니다. 어려운 개념은 아니니 해보시는 걸 추천하고요

qsef1256
2024.07.28
@팬달03

switch 자체도 최신 Java 에서는 줄여서 쓸 수 있는 문법이 많이 있습니다, enhanced switch 라고 알아보시면 될 것 같고요

qsef1256
2024.07.28
@팬달03

랜덤을 뽑는 것 자체도 숫자로 뽑기보다 뽑고 싶은 Material 내지 ItemStack 들을 모아둔 List를 만들고 거기 안에 있는 요소들을 대상으로 랜덤을 돌려서 뽑는 게 더 직관적이고 오류가 없을 것 같네요.

qsef1256
2024.07.28
@팬달03

또 ChatColor는 최신 Paper에서 deprecated로 알고 있습니다, Paper Adventure Api 등을 알아보시는 게 도움이 될 것 같고요

qsef1256
2024.07.28
@팬달03

equalsIgnoreCase도 한글 대상으로는 쓰는 의미가 별로 없습니다, 영어 대문자 소문자를 얘기하는 거니까요

qsef1256
2024.07.28
@팬달03

오류 발생을 안내하는 부분에서도 왜 오류가 발생했는지 구체적인 정보를 포함하는 것이 디버깅에 좋습니다. 지금 문제는 예상하지 않은 숫자가 나온거니 그 내용을 그대로 쓰거나 아니면 의도한 부분인 "양털을 찾지 못했습니다" 정도로 쓰는 것이 맞습니다 (다만 저는 전자를 추천합니다, 지금은 사용자한테 오류 내용이 달 되는거니 사용자 입장을 고려해서 오류 메시지를 썼지만 기본적으로 오류 메시지는 개발자가 봐야 하는 것이니 개발자한테 도움이 될만한 내용을 쓰는 게 맞고요, 숫자가 양털 색을 나타낸다는 것 자체는 또 변경될 수 있으니까 의미 그대로 쓰는 게 제일 좋을 것으로 보입니다)

qsef1256
2024.07.28
@팬달03

int random = (int) (Math.random() * 4); 이거도 사실 좀 복잡한 부분이라 계속 이렇게 쓰기 보다는 유틸리티 클래스를 하나 만들어서 좀 더 직관적으로 RandomUtil.getRandom(1, 4) 처럼 쓸 수 있도록 만드는 게 더 좋습니다 (혹은 이런 기능을 제공하는 라이브러리를 찾아보는 것이 더 좋을 수도 있습니다)

qsef1256
2024.07.28
@팬달03

String을 결합하는 것도 + 를 쓰기 보단 .formatted를 쓰는 게 가독성과 수정 할 때 편합니다

qsef1256
2024.07.28
@팬달03

그리고 onEnable에 @Override 안 달린 것 같네요

qsef1256
2024.07.28
@팬달03

지금 command도 return false; 만 하는 것 같은데 아마도 이러면 알 수 없는 명령어 입니다 내지 명령어 실패로 처리될 껍니다, 명령어가 성공한 경우 return true를 해야 이런 안내문이 안 뜹니다.

qsef1256
2024.07.28
@팬달03

그리고 크리에이티브 인 경우 "관리자 입니다" 라는 안내문이 뜨게 되어 있는데, 크리에이티브 이지만 관리자가 아닌 경우도 있을 수 있습니다, 해당 안내문은 정말 op나 특정 펄미션을 가지고 있을 때만 쓰는 것이 좋습니다. 나중에 그냥 적혀진 안내문을 보고 착각할 가능성이 있으니까요

qsef1256
2024.07.28
@팬달03

그리고 tab complete (탭 누르면 자동완성) 기능도 추가를 하면 명령어 사용하기에 더 편할껍니다.

qsef1256
2024.07.28
@팬달03

안내 문들 자체도 시스템을 따로 만들어서 안내 문을 설정 파일로 변경할 수 있게 만들면 사용할 때 편할 수도 있는데 이거는 필요에 따라서 알아보시면 될 것 같네요

qsef1256
2024.07.28
@팬달03

음 그리고 다소 주제에 벗어날 수는 있지만 랜덤 양털 뽑기 자체는 마크 자체에서 그냥 공급기를 써도 될 것 같은 부분이거든요, 플러그인 개발은 원래 이렇게 어렵고 시간이 많이 드는 일이기에 다른 방법을 쓸 수 있다면 그걸 쓰는 게 더 나을 수도 있습니다. 생각해보시는 게 좋을 것 같아요

qsef1256
2024.07.28
@팬달03

그리고 혹시나 해서 얘기를 드리는 건데, 그냥 어디서 보고 복사해서 가져오거나 아무렇게나 넣어보고 안되면 다시 해보는 코딩을 하고 있으시다면 바꾸시는 게 좋습니다, 그건 내가 이 코드를 알고서 코딩을 하는 게 아니거든요. 문제가 더 심각해질 수 있습니다. 개발자는 그런 사람이 아니거든요.

 

물론 그냥 제 착각이고 아닐 수도 있어요, 근데 지금 코드 자체가 인터넷에 많이 돌아다니는 형식이기도 하고, 정확히 이해를 하고서 코딩을 하는 건 아닌 느낌이 있어서 얘기 드려요.

팬달03
2024.07.28
@qsef1256

헤헤 진심으로 신경써주셔서 고맙습니다!

 

굳이 플러그인으로 양털을 지급하려는 이유는 플러그인 공부를 어디서부터 시작해야 할지 몰라 간단할 것 같은 것부터 만들어보자 였습니다.

 

코드는, 기본적으로 스피갓 클래스를 참고하며 만들고 있으며, 근데도 모르겠다 싶을 때는 주로 해외 사례들을 찾아보는 편입니다!

 

다시 한번 고맙습니다!