NeoForge 26.1 Docs
  • 문서
  • 노트
NeoForge 26.1
NeoForge 26.1
v26.1
학습 진도
0 / 77 챕터 완료방문 0
BlockEntity 기초 — CounterBlockEntityBlockEntityRenderer 구현Entity 등록과 AttributeSupplierEntityRenderer와 EntityModelAI Goal 시스템CustomPacketPayload — 클라이언트/서버 패킷 통신AttachmentTypes — 엔티티·블록에 데이터 부착WorldGen Feature 기초 — 광물 생성
고급 시스템

AttachmentTypes — 엔티티·블록에 데이터 부착

NeoForge AttachmentTypes(구 Capabilities)로 플레이어·엔티티·블록 엔티티에 임의 데이터를 Codec 기반으로 저장·복원하는 방법을 학습합니다.

AttachmentTypes — 엔티티·블록에 데이터 부착

NeoForge 26에서 AttachmentTypes는 플레이어, 엔티티, 청크, 블록 엔티티에 임의의 데이터를 "붙이는" 가장 현대적인 방법입니다. 구식 Capabilities API를 대체하며, DeferredRegister + Codec으로 등록·직렬화를 통일했습니다.


1. ATTACHMENT_TYPES DeferredRegister

AttachmentType도 다른 NeoForge 오브젝트와 동일하게 DeferredRegister로 등록합니다. 레지스트리 키는 NeoForgeRegistries.Keys.ATTACHMENT_TYPES입니다.

// examplemod-template-26.1.2/src/main/java/com/example/examplemod/ExampleMod.java
public static final DeferredRegister<AttachmentType<?>> ATTACHMENT_TYPES =
    DeferredRegister.create(NeoForgeRegistries.Keys.ATTACHMENT_TYPES, "examplemod");

생성자에서 이벤트 버스에 연결합니다.

// ExampleMod 생성자
public ExampleMod(IEventBus modEventBus, ModContainer modContainer) {
    ATTACHMENT_TYPES.register(modEventBus);
    ITEMS.register(modEventBus);
    BLOCKS.register(modEventBus);
    // ...
}

2. AttachmentType 선언 — MANA 예제

AttachmentType.builder(defaultValueSupplier)로 빌더를 만들고, 체이닝으로 옵션을 추가한 뒤 .build()합니다.

// examplemod-template-26.1.2/src/main/java/com/example/examplemod/ExampleMod.java
public static final Supplier<AttachmentType<Integer>> MANA = ATTACHMENT_TYPES.register(
    "mana",
    () -> AttachmentType.builder(() -> 100)         // 기본값 100
        .serialize(Codec.INT.fieldOf("mana"))        // NBT 저장 (필드명 "mana")
        .copyOnDeath()                                // 사망 시 보존
        .build()
);
빌더 옵션설명
builder(() -> 100)부착값이 없을 때 반환할 기본값 팩토리
.serialize(Codec.INT.fieldOf("mana"))NBT 저장·복원에 사용할 Codec (필드명 "mana")
.copyOnDeath()플레이어 사망 후 리스폰 시 값 보존
.build()AttachmentType 완성

3. 데이터 접근 — getData / setData / hasData

getData, setData, hasData, removeData 네 메서드로 모든 접근을 처리합니다. 메서드는 IAttachmentHolder 인터페이스에 정의되어 있으며, Player, Entity, BlockEntity, Chunk가 모두 구현합니다.

// 읽기 — 값이 없으면 기본값(100) 반환
int mana = player.getData(ExampleMod.MANA.get());
 
// 쓰기
player.setData(ExampleMod.MANA.get(), 50);
 
// 부착 여부 확인 (기본값과 구분 필요 시 활용)
boolean has = player.hasData(ExampleMod.MANA.get());
 
// 제거 — 기본값으로 리셋
player.removeData(ExampleMod.MANA.get());

이벤트 핸들러 예시

마나를 소비하고 쿨다운 처리하는 이벤트 핸들러 예시입니다.

// 예시 이벤트 핸들러 — @EventBusSubscriber(modid = "examplemod") 패턴은
// examplemod-template-26.1.2/.../events/ParticleHandlers.java 와 동일하다.
@EventBusSubscriber(modid = "examplemod")
public class ManaHandler {
 
    @SubscribeEvent
    public static void onPlayerRightClick(PlayerInteractEvent.RightClickItem event) {
        Player player = event.getEntity();
        int mana = player.getData(ExampleMod.MANA.get());
 
        if (mana >= 10) {
            player.setData(ExampleMod.MANA.get(), mana - 10);
        }
    }
}

4. Codec 사용 패턴

Codec은 직렬화(NBT → Java 객체 ↔ Java 객체 → NBT) 변환기입니다. NeoForge AttachmentType은 Minecraft가 제공하는 Codec<T>를 그대로 씁니다.

4-1. 단순 타입

.serialize(Codec.INT)       // int
.serialize(Codec.DOUBLE)    // double
.serialize(Codec.STRING)    // String
.serialize(Codec.BOOL)      // boolean

4-2. 리스트

.serialize(Codec.INT.listOf())   // List<Integer>

4-3. 복합 객체

// 커스텀 레코드 클래스의 Codec
public record ManaData(int current, int max) {
    public static final Codec<ManaData> CODEC = RecordCodecBuilder.create(inst ->
        inst.group(
            Codec.INT.fieldOf("current").forGetter(ManaData::current),
            Codec.INT.fieldOf("max").forGetter(ManaData::max)
        ).apply(inst, ManaData::new)
    );
}
 
// 등록 시
public static final Supplier<AttachmentType<ManaData>> MANA_DATA = ATTACHMENT_TYPES.register(
    "mana_data",
    () -> AttachmentType.builder(() -> new ManaData(100, 100))
        .serialize(ManaData.CODEC)
        .build()
);

5. 구식 Capabilities → AttachmentTypes 전환

항목구식 Capabilities (1.20 이하)AttachmentTypes (NeoForge 26)
API 접근entity.getCapability(CAP)entity.getData(ATTACH.get())
등록RegisterCapabilitiesEventDeferredRegister
직렬화INBTSerializable<T> 인터페이스 직접 구현Codec 자동 처리
네트워크 동기화수동 패킷 + ICapabilityProviderNeoForge 자동 sync (선택적 활성화)
기본값없음 (null 체크 필수)빌더에서 builder(() -> 기본값)
사망 시 보존PlayerEvent.Clone 이벤트에서 수동 복사.copyOnDeath() 한 줄

6. 안티패턴 — serialize 누락 시 저장 안 됨

⚠️ serialize 누락 시 저장 안 됨

// ❌ serialize() 호출 안 함 → 세계 재진입 시 데이터 손실
AttachmentType.builder(() -> 100).build();
 
// ✅ Codec 명시
AttachmentType.builder(() -> 100)
    .serialize(Codec.INT)
    .build();

serialize 없으면 메모리에만 존재 → 세계 저장 시 사라짐. 런타임에 오류가 발생하지 않기 때문에 발견하기 어렵습니다. 모든 AttachmentType에 .serialize(Codec)을 명시하는 것을 원칙으로 삼습니다.


7. 전체 흐름 다이어그램

다이어그램 렌더링 중…

요약

단계내용
1DeferredRegister<AttachmentType<?>> — NeoForgeRegistries.Keys.ATTACHMENT_TYPES
2AttachmentType.builder(기본값).serialize(Codec).copyOnDeath().build()
3생성자에서 ATTACHMENT_TYPES.register(modEventBus)
4entity.getData / setData / hasData / removeData
5Codec 선택: 단순(Codec.INT), 리스트(.listOf()), 복합(RecordCodecBuilder)

다음 챕터에서는 AttachmentType을 네트워크로 클라이언트에 동기화하는 방법을 학습합니다.

CustomPacketPayload — 클라이언트/서버 패킷 통신

NeoForge 26의 CustomPacketPayload record와 StreamCodec으로 클라이언트↔서버 패킷을 정의하고, RegisterPayloadHandlersEvent와 PacketDistributor로 전송하는 전체 과정을 학습합니다.

WorldGen Feature 기초 — 광물 생성

데이터팩 3종(configured_feature / placed_feature / biome_modifier)으로 루비 광석을 오버월드 지하에 생성하는 전체 흐름을 학습합니다.

On this page

AttachmentTypes — 엔티티·블록에 데이터 부착1. ATTACHMENT_TYPES DeferredRegister2. AttachmentType 선언 — MANA 예제3. 데이터 접근 — getData / setData / hasData이벤트 핸들러 예시4. Codec 사용 패턴4-1. 단순 타입4-2. 리스트4-3. 복합 객체5. 구식 Capabilities → AttachmentTypes 전환6. 안티패턴 — serialize 누락 시 저장 안 됨7. 전체 흐름 다이어그램요약
NeoForge 26.1 Docs

NeoForge 26.1 모딩 개발 문서 사이트

GitHubDiscord

문서

  • 문서
  • 노트

GitHub

  • GitHub
  • Discord

© 2026 NeoForge 26.1 Docs. 콘텐츠는 MIT 라이선스로 제공됩니다.

Built with Next.js · Tailwind CSS · shadcn/ui