NeoForge 26.1 Docs
  • 문서
  • 노트
NeoForge 26.1
NeoForge 26.1
v26.1
학습 진도
0 / 77 챕터 완료방문 0
@Mod 클래스와 생성자 패턴이벤트 버스 — Mod / NeoForge 두 가지 차이Registry와 DeferredRegister 개념ModConfigSpec과 설정 GUISLF4J Logger와 로그 레벨클라이언트/서버 분리와 Dist모드 내 다국어 — lang/<locale>.json
모딩 기초

@Mod 클래스와 생성자 패턴

NeoForge 26의 @Mod 어노테이션과 생성자 시그니처(IEventBus, ModContainer)를 이해하고 mod-id 매칭, 이벤트 버스 등록 방법을 학습합니다.

@Mod 클래스와 생성자 패턴

NeoForge 모드의 진입점은 딱 하나입니다. @Mod 어노테이션이 붙은 클래스, 그리고 그 생성자. 이 챕터에서는 ExampleMod.java를 한 줄씩 읽으면서 NeoForge 26이 모드를 어떻게 로드하는지 파악합니다.


1. @Mod 어노테이션

// examplemod-template-26.1.2/src/main/java/com/example/examplemod/ExampleMod.java, @Mod 어노테이션
@Mod(ExampleMod.MODID)
public class ExampleMod {
    public static final String MODID = "examplemod";

@Mod 어노테이션 하나가 FML(Forge Mod Loader)에게 "이 클래스가 모드 진입점"이라고 알립니다. 괄호 안의 문자열이 mod-id입니다.

mod-id는 세 곳에서 반드시 일치해야 합니다.

위치값
@Mod("examplemod")examplemod
neoforge.mods.toml의 modId${mod_id} → 빌드 시 examplemod로 치환
DeferredRegister.createItems(MODID)MODID 상수 참조

⚠️ 잘못된 modId 매칭

@Mod("WrongId") 와 mods.toml의 modId = "examplemod" 가 불일치하면:

Caused by: ModLoadingException: Mod class @Mod annotation does not match modId

둘은 반드시 정확히 같은 문자열이어야 합니다.


2. 정적 필드 — DeferredRegister

생성자 위에 선언된 정적 필드들을 먼저 봅니다.

// BLOCKS / ITEMS / CREATIVE_MODE_TABS — 정적 DeferredRegister 선언
public static final DeferredRegister.Blocks BLOCKS =
        DeferredRegister.createBlocks(MODID);
 
public static final DeferredRegister.Items ITEMS =
        DeferredRegister.createItems(MODID);
 
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS =
        DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID);

DeferredRegister는 "나중에 등록할 것들을 모아두는 바구니"입니다. 클래스가 로드될 때 정적 초기화로 생성되지만, 실제 레지스트리 등록은 생성자에서 register(modEventBus)를 호출할 때까지 일어나지 않습니다.

// EXAMPLE_BLOCK / EXAMPLE_BLOCK_ITEM / EXAMPLE_ITEM — 실제 게임 오브젝트 등록 (지연 방식)
public static final DeferredBlock<Block> EXAMPLE_BLOCK =
        BLOCKS.registerSimpleBlock("example_block", p -> p.mapColor(MapColor.STONE));
 
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM =
        ITEMS.registerSimpleBlockItem("example_block", EXAMPLE_BLOCK);
 
public static final DeferredItem<Item> EXAMPLE_ITEM =
        ITEMS.registerSimpleItem("example_item", p -> p.food(
                new FoodProperties.Builder().alwaysEdible().nutrition(1).saturationModifier(2f).build()));

registerSimpleBlock, registerSimpleItem은 팩토리 람다를 받아 DeferredHolder를 반환합니다. 아직 실제 객체가 만들어진 게 아닙니다. 레지스트리 이벤트가 발생할 때 비로소 생성됩니다.


3. 생성자 시그니처 (NeoForge 26)

// NeoForge 26 생성자 시그니처
public ExampleMod(IEventBus modEventBus, ModContainer modContainer) {

NeoForge 26에서 @Mod 클래스 생성자는 두 파라미터를 받을 수 있습니다. FML이 자동으로 주입합니다.

IEventBus modEventBus

Mod 이벤트 버스입니다. 모드 라이프사이클 이벤트를 처리합니다.

  • FMLCommonSetupEvent — 양쪽(서버/클라이언트) 공통 초기화
  • FMLClientSetupEvent — 클라이언트 전용 초기화
  • RegisterEvent — 레지스트리 등록 (DeferredRegister가 내부적으로 사용)
  • BuildCreativeModeTabContentsEvent — 크리에이티브 탭 콘텐츠 구성

ModContainer modContainer

모드의 메타데이터 컨테이너입니다.

  • modContainer.getModId() — mod-id 문자열
  • modContainer.getModInfo().getVersion() — 버전 정보
  • modContainer.registerConfig(...) — 설정 파일 등록

4. 생성자 내부 — 한 줄씩

// commonSetup 이벤트 리스너 등록
modEventBus.addListener(this::commonSetup);

addListener로 메서드 참조를 넘기면 해당 이벤트가 발생할 때 호출됩니다. 람다나 메서드 참조 모두 가능합니다.

// DeferredRegister를 mod 이벤트 버스에 연결
BLOCKS.register(modEventBus);
ITEMS.register(modEventBus);
CREATIVE_MODE_TABS.register(modEventBus);

DeferredRegister.register(modEventBus)가 핵심입니다. 이 호출이 없으면 바구니에 담아둔 블록/아이템이 실제 레지스트리에 등록되지 않습니다.

// 게임 이벤트 버스에 this 등록
NeoForge.EVENT_BUS.register(this);

NeoForge.EVENT_BUS는 게임 이벤트 버스입니다. modEventBus와 다릅니다. 서버 시작, 플레이어 로그인 같은 런타임 이벤트를 처리합니다. @SubscribeEvent가 붙은 메서드가 이 클래스에 있을 때만 필요합니다.

// 크리에이티브 탭 이벤트 리스너
modEventBus.addListener(this::addCreative);
 
// 설정 파일 등록
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);

5. 생성자 안에서 할 일 / 하지 말 것

해야 할 것

// 올바른 패턴
public ExampleMod(IEventBus modEventBus, ModContainer modContainer) {
    BLOCKS.register(modEventBus);          // DeferredRegister 연결
    ITEMS.register(modEventBus);
    modEventBus.addListener(this::setup);  // 이벤트 리스너 등록
    modContainer.registerConfig(...);      // 설정 등록
}

하지 말 것

// 잘못된 패턴 — 정적 초기화에서 직접 등록
static {
    // BuiltInRegistries.BLOCK.register(...) — 절대 금지
    // 레지스트리가 아직 준비되지 않은 시점에 접근하면 크래시
}
 
// 잘못된 패턴 — 생성자에서 무거운 I/O
public ExampleMod(IEventBus modEventBus, ModContainer modContainer) {
    Files.readAllBytes(Path.of("huge-data.bin")); // 로딩 시간 증가
}
패턴이유
BuiltInRegistries 직접 접근 (정적 초기화)레지스트리 준비 전 접근 → 크래시
생성자에서 무거운 I/O모드 로딩 시간 증가, 다른 모드 로딩 블로킹
@SubscribeEvent 없이 NeoForge.EVENT_BUS.register(this)불필요한 이벤트 버스 등록 (주석 참고)

6. @SubscribeEvent 패턴

// onServerStarting — 게임 이벤트 버스 구독
@SubscribeEvent
public void onServerStarting(ServerStartingEvent event) {
    LOGGER.info("HELLO from server starting");
}

NeoForge.EVENT_BUS.register(this)를 생성자에서 호출했기 때문에 이 메서드가 ServerStartingEvent 발생 시 자동으로 호출됩니다. @SubscribeEvent가 붙은 메서드가 없다면 register(this) 호출 자체가 불필요합니다.

⚠️ 구식 패턴 주의

NeoForge 26 이전 버전에서는 @Mod.EventBusSubscriber 어노테이션을 클래스에 붙이는 방식도 있었습니다. 현재 권장 방식은 생성자에서 modEventBus.addListener(...) 또는 NeoForge.EVENT_BUS.register(this)를 명시적으로 호출하는 것입니다.


7. 두 이벤트 버스 정리

modEventBus (IEventBus)NeoForge.EVENT_BUS
용도모드 라이프사이클게임 런타임 이벤트
예시FMLCommonSetupEvent, RegisterEventServerStartingEvent, PlayerEvent
등록 방법modEventBus.addListener(...)NeoForge.EVENT_BUS.register(this)
주입 시점생성자 파라미터로 자동 주입정적 필드로 접근

다음 챕터에서는 이 두 이벤트 버스의 차이를 더 깊이 파고듭니다. 어떤 이벤트가 어느 버스에 속하는지, 잘못 등록하면 어떤 일이 생기는지 살펴봅니다.


요약

  • @Mod("examplemod")의 문자열은 neoforge.mods.toml의 modId와 정확히 일치해야 합니다.
  • NeoForge 26 생성자는 IEventBus와 ModContainer를 파라미터로 받습니다. FML이 자동 주입합니다.
  • DeferredRegister.register(modEventBus) 호출이 없으면 블록/아이템이 등록되지 않습니다.
  • modEventBus는 라이프사이클 이벤트, NeoForge.EVENT_BUS는 런타임 이벤트입니다.

IntelliJ 디버거와 Hot Reload

IntelliJ IDEA의 Debug 모드로 runClient를 실행하여 breakpoint를 활용한 디버깅 방법과 Hot Reload(코드 변경 즉시 반영)의 사용법을 익힙니다.

이벤트 버스 — Mod / NeoForge 두 가지 차이

NeoForge 26의 Mod EventBus와 NeoForge EventBus 두 가지를 구분하고 어느 이벤트가 어느 버스에 가는지, 등록 방식 4가지를 학습합니다.

On this page

@Mod 클래스와 생성자 패턴1. @Mod 어노테이션2. 정적 필드 — DeferredRegister3. 생성자 시그니처 (NeoForge 26)IEventBus modEventBusModContainer modContainer4. 생성자 내부 — 한 줄씩5. 생성자 안에서 할 일 / 하지 말 것해야 할 것하지 말 것6. @SubscribeEvent 패턴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