이번에는 마인크래프트에서 작물이 얼마나 성장했는지 알려주는 플러그인을 개발해보도록 하겠습니다.
우선 플러그인을 개발하기 앞서 플러그인의 설계와 마인크래프트에서 작물은 어떻게 성장하는지에 대해 알아보도록 하겠습니다.
우리가 만들 플러그인은
유저가 우클릭을 할 경우
작물이 얼마나 성장했는지
유저에게 전달해주는
플러그인 입니다.
마인크래프트에서는 틱이라는 시간의 개념이 존재합니다.
Tick – Minecraft Wiki (fandom.com)
Tick
Nearly all video games (including Minecraft) are driven by one big program loop. Just as every gear in a clock is synchronized with the pendulum, every task involved in advancing a game simulation is synchronized with the game loop. Appropriately, one cycl
minecraft.fandom.com
우리가 초, 분, 시간 이라는 개념이 있듯이 마인크래프트는 틱 이라는 개념이 있는 것입니다.
마인크래프트에서 1 tick 은 0.05 초 입니다.
그렇다면 1 초는 20 tick 이고
마인크래프트에서 하루는 24000 tick, 실제 시간으로는 20 분 입니다.
마인크래프트에서는 Random Tick 이라는 개념이 존재하는데요.
청크 내의 가로 세로 높이 16 * 16 * 16 = 4096 개의 블록 중 N 개가
한 틱에 영향을 받게 된다는 것입니다.
자바 에디션의 경우 randomTickSpeed 라는 명령어를 통해 영향을 받을 블록의 갯수를 조절할 수 있고 디폴트는 3 입니다.
농작물의 성장도 위 Random tick 의 영향을 받는데요.
한 틱 마다 4096 개의 블록 중 3개의 블록만이 영향을 받는다는 의미입니다.
농장물도 1 tick 마다 청크 주위의 4096 개의 블록 중 3개의 블록이 선택되면 성장하게 되는 구조인 것입니다.
그러면 다시 돌아와
기능을 하나씩 개발해보도록 하겠습니다.
유저가 우클릭을 할 경우 를 먼저 개발해보도록 하겠습니다.
유저가 우클릭을 한다는 것도 이벤트의 종류일 확률이 높습니다.
그렇기에 구글에 spigot player right click 으로 검색해보도록 하겠습니다.
Right Click Event | SpigotMC - High Performance Minecraft
관련된 내용을 살펴보니 PlayerInteractionEvent 를 활용하라고 합니다.
PlayerInteractEvent (Spigot-API 1.21.1-R0.1-SNAPSHOT API) (spigotmc.org)
PlayerInteractEvent (Spigot-API 1.21.1-R0.1-SNAPSHOT API)
All Implemented Interfaces: Cancellable Represents an event that is called when a player interacts with an object or air, potentially fired once for each hand. The hand can be determined using getHand(). This event will fire as cancelled if the vanilla beh
hub.spigotmc.org
폴더의 구조는 위와 같이 Listener Class 와 main Class 를 구분합니다.
package com.tistory.beingb.listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEvent;
public class PlantGrowthPluginListener implements Listener {
@EventHandler
public void onCheckPlantGrowth(PlayerInteractEvent event) {
}
}
위와 같이 PlayerInteractEvent 를 활용하는 EventHandler 를 선언합니다.
PlayerInteractEvent 는 마인크래프트에서 왼손과 오른손을 구분하면서 버그처럼 보이는 문제가 하나 추가됐는데요.
PlayerInteractEvent 는 무언가 Action 을 했을 때 두 번 호출되는 문제가 발생한다고 합니다.
위 코드 처럼 OFF_HNAD 로 발생하는 이벤트는 무시하고
HAND 에서 발생하는 이벤트만 정상적으로 작동하도록 하는 것입니다.
그 다음 유저가 우클릭 했을 때 이벤트가 작동하도록 합니다.
그 다음으로는 클릭한 블록이 농작물이 맞는지 판단해야 하는데요.
농작물의 경우 시간이 흐름에 따라 성장하고 모든 성장을 마치게 되면 수확을 할 수 있습니다.
Wheat Seeds
Wheat seeds (in Java Edition) or seeds (in Bedrock Edition)[until BE 1.21.30] are items obtained by breaking grass, or more abundantly harvested from wheat crops, and are used to plant them.
minecraft.wiki
밀의 경우는 초기 단계부터 총 8 개의 단계로 나뉘어져 있고
이런 stages 는 block 의 age 라는 값으로 확인할 수 있는 것 같습니다.
Ageable 라는 기능을 통해 작물의 현재 스테이지를 확인할 수 있다는 것을 알 수 있었습니다.
그러면 블록이 Ageable 인터페이스 타입인지 확인하는 작업이 필요한데요.
클릭한 블록의 데이터가 Ageable 인스턴스가 아닌 경우에 이벤트를 작동시키지 않도록 합니다.
만약, 우클릭한 블록이 Ageable 인스턴스인 블록이 아니라면 해당 코드에 걸려 이벤트를 작동시키지 않을 것입니다.
그 다음 BlockData 가 Ageable 의 하위 클래스 이므로
Ageable 의 getAge 와 getMaximumAge 메서드를 활용하기 위해
BlockData 클래스의 타입을 캐스팅을 활용해 Ageable 클래스로 좁힙니다.
그러면 getAge 메서드를 통해 현재 농작물의 단계를 확인할 수 있고
getMaximumAge 메서드를 통해 현재 농작물의 최대 단계를 확인할 수 있습니다.
만약, 밀 씨앗이 위와 같은 단계이면
getAge 는 2 라는 값을 돌려주고,
getMaximumAge 는 7 이라는 값을 돌려주게 되는 것입니다.
일반 게임에 참여하는 유저는 0 부터 시작하는 것에 익숙하지 않을 수 있기에 값들에 + 1 을 해줘서
상황에 맞는 문구를 출력시킵니다.
package com.tistory.beingb.listener;
import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
public class PlantGrowthPluginListener implements Listener {
@EventHandler
public void onCheckPlantGrowth(PlayerInteractEvent event) {
Player player = event.getPlayer();
Action action = event.getAction();
if (event.getHand() == EquipmentSlot.OFF_HAND)
return;
if (!action.equals(Action.RIGHT_CLICK_BLOCK))
return;
Block clickedBlock = event.getClickedBlock();
BlockData clickedBlockData = clickedBlock.getBlockData();
if (!(clickedBlockData instanceof Ageable))
return;
Ageable ageableBlockedData = (Ageable) clickedBlockData;
int currentAge = ageableBlockedData.getAge();
int maximumAge = ageableBlockedData.getMaximumAge();
if (currentAge == maximumAge) {
player.sendMessage("현재 해당 작물은 모두 성장한 상태입니다.");
} else {
player.sendMessage(
"현재 해당 작물의 성장 단계는 " + (currentAge + 1) + " 딘계 이고, 최대 " + (maximumAge + 1) + " 단계까지 성장할 수 있습니다.");
}
}
}
그리고 빼먹지 않고 메인 클래스의 플러그인 매니저에 이벤트를 등록해줍니다.
package com.tistory.beingb.main;
import org.bukkit.plugin.java.JavaPlugin;
import com.tistory.beingb.listener.PlantGrowthPluginListener;
public class PlantGrowthPlugin extends JavaPlugin {
@Override
public void onDisable() {
// TODO Auto-generated method stub
super.onDisable();
}
@Override
public void onEnable() {
// TODO Auto-generated method stub
super.onEnable();
this.getServer().getPluginManager().registerEvents(new PlantGrowthPluginListener(), this);
}
@Override
public void onLoad() {
// TODO Auto-generated method stub
super.onLoad();
}
}
플러그인으로 만들어 정상적으로 작동하는지 테스트해보도록 하겠습니다.
밀 씨앗이 위와 같은 상태일 때 오른쪽 클릭을 하면
현재의 단계와 자랄 수 있는 최대 단계를 알려주고 있습니다.
작물이 모두 자란 상태에서 오른쪽 클릭 시 모두 성장한 상태라는 문구를 노출합니다.
밀이 7 단계 일 때와 8 단계의 경우에는 생김새가 비슷해서
지금 수확해도 괜찮은지 헷갈리는 경우가 많은데요.
위 플러그인을 통해 모두 성장한 상태에서 수확할 수 있습니다.
'마인크래프트' 카테고리의 다른 글
12. 마인크래프트 플러그인 개발 - 더블 점프 플러그인 개발 (1) | 2024.11.01 |
---|---|
11. 마인크래프트 플러그인 개발 - 커스텀 아이템 플러그인 개발 (1) | 2024.08.31 |
9. 마인크래프트 플러그인 개발 - 챗컬러 플러그인 개발 (0) | 2024.08.24 |
7. 마인크래프트 플러그인 개발 - 데미지 디스플레이 플러그인 개발 (0) | 2024.08.16 |
6. 마인크래프트 플러그인 개발 - Listener 활용 (0) | 2024.08.16 |