본문 바로가기
마인크래프트/플러그인 제작 강좌(자바)

[자바로 마크 Paper 플러그인 만들기]8. 총 만들기(2) - 커스텀 모델 아이템 적용법(플러그인으로 텍스처 적용하기)

by Zepelown 2025. 3. 4.

*본 강의는 1.20.2 Paper 기준으로 제작되었습니다*

 

이전 강의

(참고하면 너무 좋아요!)

[자바로 마크 Paper 플러그인 만들기]7. 총 만들기(1) - 커스텀 아이템 제작하는 법

 

[자바로 마크 Paper 플러그인 만들기]7. 총 만들기(1) - 커스텀 아이템 제작하는 법

*본 강의는 1.20.2 Paper 기준으로 제작되었습니다* 이전 강의(참고하면 너무 좋아요!)[자바로 마크 Paper 플러그인 만들기]6. 주기적으로 공지사항 띄우기 [자바로 마크 Paper 플러그인 만들기]6. 주기

zepelown.tistory.com

 

강의에 사용한 전체 코드

Zepelown/PaperBlogPosting: Minecraft Paper API Blog Posting Repository (github.com)

 

GitHub - Zepelown/PaperBlogPosting: Minecraft Paper API Blog Posting Repository

Minecraft Paper API Blog Posting Repository. Contribute to Zepelown/PaperBlogPosting development by creating an account on GitHub.

github.com

 


미리 보는 결과물

 

그림 1. 커스텀 모델이 적용된 권총

 


개요

그림 2. 커스텀 모델 적용 이전의 아이템 모습

 

이전에 총을 만들었으나 아이템이 말갑옷이라 멋이 없었습니다.

 

진짜 총같게 텍스처를 입혀보겠습니다.

 

플러그인으로도 모드처럼 사용자가 정의한 텍스처를 입힐 수 있는데

 

이걸 커스텀 모델이라고 합니다.

 

커스텀 모델 적용을 위해선 리소스팩을 필요합니다.

 

리소스팩을 제작해서 커스텀 모델까지의 적용을 간단하게 다루겠습니다.

 

 


리소스팩 만들기

paperEdu_Zepelown.zip
0.01MB

 

위 리소스팩은 제가 강좌를 위해 만든 리소스팩입니다.

 

참고) 리소스팩 적용법

더보기

 

윈도우 검색창에 %appdata% 를 입력하고 들어갑니다.

 

.minecraft -> resourcepacks 에 들어갑니다.

 

여기에 zip를 두시면 됩니다.

(압축을 풀어도 됩니다)

마인크래프트 설정에 가서 리소스팩을 활성화 해줍니다.

 


내부엔 총이랑 총알 텍스처가 들어있습니다.

(총알 설정법은 다루지 않습니다. 직접 해보세요!)

 

이 리소스팩을 바로 사용하고 코딩 부분으로 넘어가셔도 되지만

 

응용을 하기 위해선 어떤 구조인지 아셔야 합니다.

 

구조에 대해 설명해드리겠습니다.

 

먼저, 압축 파일을 풀어보세요.

 

.minecraft/resourcepacks/paperEdu_Zepelown/
│── assets/
│   ├── minecraft/
│   │   ├── models/
│   │   │   ├── item/
│   │   │   │   ├── golden_horse_armor.json  ← (금으로된 말 갑옷 모델 데이터)
│   │   │   │   ├── pistol.json  ← (권총의 모델 데이터)
│   │   ├── textures/
│   │   │   ├── item/
│   │   │   │   ├── pistol.png  ← (권총 텍스처)
│── pack.mcmeta  ← (리소스팩 정보 파일)

 

폴더 구조는 위와 같이 되어 있습니다.

 

먼저 pack.mcmeta부터 보겠습니다.

pack.mcmeta

{
    "pack":
    {
        "pack_format":18,
        "description":"paperEdu blog posting made By Zepelown"
    }
}

 

여기서 중요한 건 pack_format입니다.

 

이는 마크 버전마다 다 다릅니다.

 

pack_format – Minecraft Wiki

 

Pack format

pack_format, sometimes referred to as pack_version, is a version number used to group Java Edition versions with compatible assets. This number is used in: version.json pack.mcmeta This number is used to declare the format of a resource pack in pack.mcmeta

minecraft.fandom.com

위 사이트에서 버전에 맞는 pack_format을 확인할 수 있습니다.

 

1.20.1은 15, 1.20.2는 18로 설정하시면 됩니다.

(올려둔 리소스팩은 18로 설정되어 있으니 다른 버전은 직접 수정하시면 됩니다)

 

minecraft ... models & textures

.minecraft/resourcepacks/paperEdu_Zepelown/
│── assets/
│   ├── minecraft/
│   │   ├── models/
│   │   │   ├── item/
│   │   │   │   ├── golden_horse_armor.json  ← (금으로된 말 갑옷 모델 데이터)
│   │   │   │   ├── pistol.json  ← (권총의 모델 데이터)
│   │   ├── textures/
│   │   │   ├── item/
│   │   │   │   ├── pistol.png  ← (권총 텍스처)
│── pack.mcmeta  ← (리소스팩 정보 파일)

 

모델과 텍스처는 1대1의 관계를 갖습니다.

 

텍스처는 말 그대로 텍스처라 이미지 파일입니다.

 

그러면 모델은 뭘까요?

 

모델은 텍스처를 어떤 아이템에 어떻게 적용할지를 나타냅니다.

 

여기선 pistol.json과 pistol.png가 1대1로 매칭이 됩니다.

 

한번 확인해보겠습니다.

 

pistol.json

{
    "parent": "minecraft:item/generated",
    "textures": {
      "layer0": "minecraft:item/pistol"
    }
  }

 

parent는 여러 가지 종류가 있습니다.

 

여기선 단순히 아이템에 텍스처를 입히면 끝이기 때문에 item/generated로 처리합니다.

 

부모 모델의 값을 상속받는 것으로 item/stairs, item/slab, item/armor 등의 다른 것도 있습니다.

 

예를 들어, stairs는 텍스처를 계단에 맞게 바꿔주는 겁니다.

 

textures 부분은 실제 텍스처를 맵핑 시키는 것으로

 

현재 텍스처의 경로를 textures/item/pistol로 했기 때문에 위와 같이 작성된겁니다.

 

 

golden_horse_armor.json

.minecraft/resourcepacks/paperEdu_Zepelown/
│── assets/
│   ├── minecraft/
│   │   ├── models/
│   │   │   ├── item/
│   │   │   │   ├── golden_horse_armor.json  ← (금으로된 말 갑옷 모델 데이터)
│   │   │   │   ├── pistol.json  ← (권총의 모델 데이터)
│   │   ├── textures/
│   │   │   ├── item/
│   │   │   │   ├── pistol.png  ← (권총 텍스처)
│── pack.mcmeta  ← (리소스팩 정보 파일)

 

아까 텍스처와 모델은 1대1 매핑이 된다고 했는데

 

golden_horse_armor.json은 뭘까요??

 

이건 기존 마크 안에 존재하는 golden_horse_armor.json를 덮어씌우는 느낌으로 생각하시면 됩니다.

 

그러면 뭘 위해 덮어 쓰기를 하는 걸까요??

 

{
    "parent": "item/generated",
    "textures": {
      "layer0": "item/golden_horse_armor"
    },
    "overrides": [
      {
        "predicate": {
          "custom_model_data": 1
        },
        "model": "minecraft:item/pistol"
      }
    ]
}

 

보시면 parent와 texture는 이전과 비슷합니다.

 

추가된 것이 overrides  즉, 덮어쓰인 부분입니다.

 

여기엔 커스텀 모델 데이터 값과 그 값과 연결한 모델을 지정합니다.

 

여기서 임의로 1로 지정했고 아무 숫자로 지정하셔도 상관없습니다.

 

이렇게 1은 아까 만든 pistol.json과 연결이 된겁니다.

 

리소스팩은 이제 끝났습니다.

 

플러그인에서 총 아이템을 줄 때, 커스텀 모델 데이터 값인 1을 넣어 주기만 하면 적용이 됩니다.

 

 


플러그인 수정하기

커스텀 모델 데이터 입히기

이건 기존에 gun.util에 있던 GunBuilder 클래스를 수정하면 됩니다.

 

util.GunBuilder.java

package org.blog.paperedu.weapon.gun.util;

import org.blog.paperedu.weapon.gun.domain.model.bullet.Bullet;
import org.blog.paperedu.weapon.gun.domain.model.gun.Gun;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;

import java.util.Arrays;

public class GunBuilder {

	...

    public static ItemStack buildGun(Material type, int amount, String displayName, String customItemTag,int customModelData, String... lore) {
        ItemStack stack = new ItemStack(type, amount);
        ItemMeta meta = stack.getItemMeta();
        meta.getPersistentDataContainer().set(Gun.TAG_KEY, PersistentDataType.STRING, customItemTag);
        meta.setCustomModelData(customModelData);
        meta.setDisplayName(displayName);
        meta.setLore(Arrays.asList(lore));
        stack.setItemMeta(meta);
        return stack;
    }
    
    ....
}

 

위 메서드를 추가하면 됩니다.

 

커스텀 모델 데이터 값을 받기 위해 파라미터를 추가했으며,

 

이를 meta 인스턴스에서 setCustomModelData 메서드로 수정이 가능합니다.

 

이게 끝입니다.

 

그러면 이제 총 아이템을 주는 메소드만 수정하면 끝이겠죠.

 

model.gun.NormalPistol.java

package org.blog.paperedu.weapon.gun.domain.model.gun;

import org.blog.paperedu.weapon.gun.common.GunSoundConstant;
import org.blog.paperedu.weapon.gun.domain.model.bullet.Bullet;
import org.blog.paperedu.weapon.gun.domain.model.bullet.BulletType;
import org.blog.paperedu.weapon.gun.util.GunBuilder;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;

public class NormalPistol implements Gun {
	...
    
    private static final int customModelData = 1;
    
  	...
    
    @Override
    public void giveGunToPlayer(Player player) {
        ItemStack itemStack = GunBuilder.buildGun(
                Gun.DEFAULT_MATERIAL,
                1,
                "딱총",
                GUN_TAG,
                customModelData,
                "평범한 딱총이다"
        );
        itemStack.getItemMeta().getPersistentDataContainer().set(CURRENT_AMMO_TAG_KEY, PersistentDataType.INTEGER, MAX_AMMO);
        player.getInventory().addItem(itemStack);
    }
    
    ...
}

 

giveGunToPlayer 메서드에서 커스텀 모델 데이터를 넘겨주기만 하면 됩니다.

 

커스텀 모델은 상수이니 static final로 선언해주었습니다.

 

만들어진 결과물

그림 3. 결과물

 

댓글