강좌/Minecraft Mod 제작2015. 12. 14. 01:06

강의 환경 : forge-1.7.10-10.13.0.1230-1.7.10

배경 지식 : 텍스처

선행 과정 : 커스텀 블록 제작, 블록 메타데이터

강의 목표 :

  1. 블록에 텍스처를 부여할 있다.

  2. 메타데이터 값을 불러오고 이용하는 방법을 안다.

주의: 이 강좌는 1.8+에서 완전히 변경된 부분에 대한 강좌입니다.

 

지금까지 여러분은 자신만의 블록을 만들어 볼 수 있었습니다!

 

하지만 슬프게도 분홍색과 검은색 체크무늬가 그려진 모습밖에 보실 수 없었겠지요.

 

그래서 이번 강좌에서는 블록에 텍스처를 부여하는 방법 강좌를 하고자 합니다.

 

1. 블록의 6면에 같은 텍스처 부여하기

이 부분은 커스텀 블록 제작 강좌에서 이미 다뤘던 내용입니다.

 

Block#setTextureName(String textureName)을 이용하시면 됩니다.

 

 

이때 textureName은 '(모드 ID):(텍스처 이름)' 의 형식이고,

 

실제 경로는 '프로젝트 경로/src/main/resources/assets/(모드 ID)/textures/blocks/(텍스처 이름).png' 에 해당하게 됩니다.

 

이제 6면이 같은 색으로 된 블록을 확인하실 수 있습니다.

 

 

2. 방향과 메타데이터에 따라 다른 블록 텍스처 적용하기

 

이번에는 방향과 메타데이터에 따라 다른 블록 텍스처를 적용하는 방법을 알아봅시다.

 

그러기 위해 텍스처(Icon, 아이콘)을 등록하고, 배정하는 단계를 거쳐야 합니다.

 

  • 아이콘 등록하기

    우선 사용하고자 하는 텍스처를 아이콘으로 등록하는 방법을 알아봅시다.

     

    먼저 Block#registerBlockIcons(IIconRegister register)를 오버라이딩해야 합니다.

     

    이 메소드는 마인크래프트에 블록의 텍스처가 로딩될 때 자동으로 호출되며, 이 메소드가 갖는 인자 'IIconRegister register'를 통해 아이콘을 특정 경로로부터 가져올 수 있습니다.

     

    예를 들어, 다음과 같은 위치에 이미지가 있다고 합시다.

    '프로젝트 경로/src/main/resources/assets/(모드 ID)/textures/blocks/(텍스처 이름).png'

     

    이때 IIconRegister#registerIcon("(모드 ID):(텍스처 이름)")를 이용하여 이 이미지에 해당하는 아이콘(IIcon)을 가져올 수 있습니다.

     

    이렇게 가져온 아이콘을 저장해 주시면 됩니다.

     

    단, IIcon과 registerBlockIcons는 클라이언트(minecraft.exe)에만 존재하기 때문에, 관련 멤버변수나 메소드 선언시 @SideOnly(Side.CLIENT)를 반드시 윗줄에 써 주어야 합니다!

     

    다음은 예제입니다.

     

    텍스쳐 경로:

     

    코드:

     

  • 아이콘 배정하기

    이제 각 면에 메타데이터에 따라 다른 아이콘을 배정해 보아야겠죠?

     

    그러기 위해서는 Block#getIcon(int side, int meta)를 이용하시면 됩니다!

     

    이때 meta는 메타데이터이고, side는 다음과 같습니다.

    0 : DOWN, 아래 방향

    1 : UP, 위 방향

    2 : NORTH, 북쪽 방향

    3 : SOUTH, 남쪽 방향

    4 : WEST, 서쪽 방향

    5: EAST, 동쪽 방향

    각 경우에 맞도록 아이콘을 리턴해 주시면 됩니다. 단, 이 메소드 역시 @SideOnly(Side.CLIENT)가 필요합니다.

     

    예제로 돌아가서, 방향을 갖는 메타데이터 블록에 텍스처를 배정해 봅시다.

     

    앞면에는 tutorialfront, 윗면/아랫면에는 tutorialtop, 나머지에는 tutorial을 부여해서 방향을 구별하도록 합시다.

     

    위/아랫면의 경우 side는 0과 1이 되겠죠?

     

    그리고 앞면의 경우에는 향하는 방향을 메타데이터로 했으니, side와 일치하는 방향인지를 보면 됩니다.

    (이때 메타데이터는 4방향, side는 6방향을 표시하므로 값은 다릅니다. 다행히도 directionToFacing이라는 배열로 변환이 가능합니다.)

     

    결과적으로 다음과 같이 구현됩니다.

     

    다음과 같이 잘 된다는 것을 알 수 있습니다.

     

     

    • 포지forge-1.7.10-10.13.0.12xx-1.7.10 버전 이상에서는 수정해야 할 사항이 하나 있습니다.

      TileEntity가 아닌 모든 블록에 대해 onBlockAdded가 onBlockPlaced 호출 전후에 1번씩 호출되므로,

      메타데이터가 0인 경우에만 onBlockAdded에서 메타데이터를 설정하도록 해 주어야 합니다. 다음과 같이.

       

 

3. 위치에 따라 블록의 텍스처 적용하기

이제 위치에 따라 다른 블록 텍스처를 적용하는 방법을 알아봅시다. (멀티블록 구조와 타일엔티티에 필요합니다.)

 

우선 2번의 아이콘 등록 단계는 똑같이 해 주시고, 배정 단계만 달리해 주시면 됩니다.

 

여기서는 meta와 side를 이용한 버전 대신 Block#getIcon(IBlockAccess world, int x, int y, int z, int side)를 이용해서 배정하면 됩니다.

 

world은 블록이 속한 월드이고, x, y, z는 좌표이며, side는 아까 알아봤던 방향입니다.

 

이렇게 작은 차이만 있으니 예제는 제공하지 않습니다. 한번 직접 해 보세요!

 

(+ 관련 예제를 타일엔티티 편에서 다룰 예정입니다)

 

Posted by Abastro
강좌/Minecraft Mod 제작2015. 11. 11. 23:00

강의 환경 : forge-1.7.10-10.13.0.1160-1.7.10

배경 지식 : 데이터 

선행 과정 : 커스텀 블록 제작

강의 목표 :

  1. 블록의 메타데이터를 이해할 있다.

  2. 메타데이터 값을 불러오고 이용하는 방법을 안다.

주의: 이 강좌는 1.8+에서 완전히 변경된 부분에 대한 강좌입니다.

 

이번 강좌에서는 블록의 메타데이터에 대해 알아보도록 하겠습니다.

 

1. 메타데이터란?

 

메타데이터란, 월드의 특정 위치에 있는 블록에 지정된 추가적인 데이터입니다.

 

 

이를테면, 위 사진에서 화로에도 메타데이터가 추가로 저장됩니다.

 

뿐만 아니라, 그 아래에 있는 흙 블록에도, 심지어 공기 블록까지 모두 메타데이터를 저장하고 있습니다.

 

한 마디로 말하자면, 월드에 존재하는 모든 블록에 블록 타입(ID)과 함께 저장되는 것이 메타데이터입니다!

 

이 메타데이터는 다양한 목적에 쓰이는데, 그 예로 다음과 같은 것들이 있습니다:

 

1. 블록이 놓인 방향 (화로의 경우 4가지, 디스펜서의 경우 6가지 방향이 있습니다)

2. 물 수위 (가마솥) 혹은 레드스톤 밝기, 작물의 성장 정도

3. 침대에서의 위치, 문의 열림 여부

4. 색 등의 종류 (양털, 스테인드글라스, 묘목 등)

 

이러한 메타데이터는 4비트의 데이터로서, 0~15까지 16가지의 데이터밖에 표현할 수 없습니다(…)

 

하지만 간편하게 쓸 수 있는 만큼 상당히 많이 사용됩니다.

 

이제부터 이 메타데이터를 사용하는 방법을 알아보도록 하겠습니다!

 

 

2. 메타데이터 이용 방법

 

메타데이터는 보통 평범한 int 값으로 주어집니다. 0~15 사이의 값이죠.

 

이 값을 가져오고, 저장하며, 적절히 이용할 줄 알면 됩니다.

 

1. 메타데이터 가져오기(구하기)

 

일반적인 경우 사용하고자 하는 메소드에 메타데이터가 주어지는 경우가 많습니다.

 

그렇지 않은 경우에도, 해당 블록의 위치(x,y,z좌표)와

 

월드 인스턴스에 해당하는 World 혹은 IBlockAccess객체를 갖고 있다면,

 

World#getBlockMetadata(int x, int y, int z) 혹은 IBlockAccess의 동일한 메소드를 사용하면 됩니다.

 

(+ 블록도 getBlock(int x, int y, int z)로 가져올 수 있습니다)

 

2. 메타데이터 저장하기

 

반대로 메타데이터를 지정하고 싶다면 어떻게 해야 할까요?

 

다음 2가지 메소드를 이용하시면 됩니다.

 

World#setBlock(int x, int y, int z, Block block, int metadata, int flag)

이 메소드는 x, y, z 좌표에 있는 블록을 바꾸되,

 

블록 타입이 block, 메타데이터가 metadata가 되도록 지정합니다.

 

이때 flag는

- 1은 블록 업데이트 메소드를 호출합니다.

- 2는 패킷을 클라이언트로 보냅니다.

- 4는 블록이 렌더링되는 것을 막습니다.

이들을 더한 플래그를 사용하면 더해진 작업들이 모두 수행됩니다.

즉 3을 선택하면 업데이트 메소드를 호출하고 패킷을 보내며,

7을 선택하면 모든 작업이 실행됩니다.

 

한편 메타데이터만 바꾸는 방법도 있는데요,

 

World#setBlockMetadataWithNotify(int x, int y, int z, int metadata, int flag)

 

이 메소드를 이용하면 메타데이터만 바꿀 수 있습니다.

 

3. 메타데이터에 여러 데이터 담기

 

만약 울타리 문처럼 종류와 방향을 함께 저장하고 싶다면 어떻게 해야 할까요?

 

이 경우 방향은 2가지, 종류는 4가지라 해 봅시다.

 

그러면 2*4=8이므로 공간은 충분함을 알 수 있습니다.

 

그럼 다음과 같이 하면 됩니다:

 

메타데이터를 meta라 합시다.

이때 meta%4 를 종류, meta / 4를 방향이라 하면,

종류는 0,1,2,3 중의 하나의 값, 방향은 0,1중의 하나의 값이 됩니다.

각각의 수들에 의미를 부여하면 되겠죠.

반대로 종류를 sp, 방향을 dir이라 하면,

메타데이터는 간단히 sp + dir * 4가 됩니다.

 

비트 연산을 잘 아신다면,

4가 거듭제곱수이므로 <<2, &3과 같은 연산자를 활용하셔도 됩니다.

 

 

3. 메타데이터의 기본적인 응용

 

이제 메타데이터를 응용하여 몇 가지 작업을 해 봅시다!

 

1. 블록 설치 시 메타데이터 지정하기

 

주로 메타데이터는 블록의 방향과 같은 데이터를 저장하는 데 쓰입니다.

 

따라서 블록이 설치될 때 이런 데이터를 결정해 주어야겠죠.

 

커스텀 블록 제작 강좌까지의 과정을 거친 블록에 이를 적용해 보도록 하겠습니다.

 

 

위와 같이 onBlockAdded, onBlockPlacedBy 2개의 메소드를 필요로 합니다.

 

이들은 블록이 설치될 때 호출되는 메소드인데,

 

일반적으로 onBlockAdded는 항상 호출되며, 엔티티가 설치한 경우 onBlockPlacedBy가 그 뒤에 호출됩니다.

 

onBlockAdded에서는 열린 부분을 향하도록,

 

onBlockPlacedBy에서는 블록을 설치한 엔티티를 향하도록 해 봅시다.

 

이때 Direction 클래스를 이용하면 방향을 좀 더 쉽게 구현할 수 있습니다.

(0: 남쪽, 1: 서쪽, 2: 북쪽, 3: 동쪽 이 됩니다.)

 

우선 onBlockAdded 메소드에서는 각각의 방향에 대해서 체크하되,

 

위의 코드는 바라보고 있는 방향의 facing블록은 투명하고, 반대의 블록은 불투명할 때

 

그 방향으로 블록을 설치하도록 해줍시다.

 

(*서버인지를 체크하기 위해 '!world.isRemote'를 이용합니다)

 

 

그럼 위와 같이 됩니다.

 

여기서 Block#func_149730_j()는 제 포지 버전에서 아직 해석되지 않은 메소드인데, 해석된 경우 Block#isOpaque()의 형태일 겁니다.

 

이를 통해 이쪽 방향의 블록이 불투명한 블록인지를 판단합니다.

 

그 다음 onBlockPlacedBy 메소드는 엔티티가 향하는 반대 방향을 향하도록 해주어야겠죠?

 

그러러면 우선, 엔티티가 위의 방위들 중에서 어느 방향을 향하는지 구해야 합니다.

 

엔티티가 향하는 방향은 rotationYaw가 결정하는데,

 

남쪽에서 0.0도의 값을 갖고 시계방향으로 돌아가며 360.0도까지 증가합니다.

 

여기에 360으로 나눈 다음 4를 곱하면 남, 서, 북, 동에서 각각 0, 1, 2, 3의 값을 갖게 됩니다.

 

반올림하기 위해 0.5를 더하고 정수부분만 추출하면 방위에 해당하는 값을 얻을 수 있습니다.

 

이제 반대편을 향하기 위해 2를 더해주면 됩니다.

 

 

코드로 작성하면 위와 같이 간단합니다(…)

 

2. Pending…

 

Posted by Abastro
강좌/Minecraft Mod 제작2015. 11. 9. 15:51

강의 환경 : forge-1.7.10-10.13.0.1160-1.7.10

강의 목표 :

1. 서버와 클라이언트의 개념을 이해할 있다.

2. 프록시를 이용하여 서버와 클라이언트 코드를 통일적으로 작성할 있다.

 

 

이 강좌에서는 예고했던 대로 프록시에 대해서 다뤄보도록 하겠습니다.

 

프록시를 간단히 설명하자면, 마인크래프트 서버 측과 클라이언트 측의 차이를 해결하기 위한 방법입니다.

 

헌데 모드에서의 서버와 클라이언트는 일반적으로 알고 있는 것과 다르므로 이 부분부터 짚고 넘어가도록 하겠습니다.

 

서버 (Server)

클라이언트(Client)

위치

- 마인크래프트 서버 (항상 활성)

- 마인크래프트 클라이언트

* 싱글플레이 중 활성

* LAN서버가 열려 있을 시에도 활성

마인크래프트 클라이언트

(항상 활성)

도식

역할

* 마인크래프트 월드 전체를 담당

(전지적 시점에서 월드를 컨트롤)

 

* ex) 월드 생성 및 저장,

엔티티(몹) 스폰 및 관리,

블록 상태 관리,

인벤토리 관리,

폭발, 불 등의 기작 제어 등

 

(엔티티에는 플레이어도 포함됩니다.)

* 마인크래프트 월드를 1인칭 시점에서 플레이어에게 보여주는 역할

(클라이언트에도 (관상용) 월드는 존재)

 

*서버의 행동을 그대로 따라하며

결과를 보여줌

 

* 플레이어의 행동은 대부분 패킷을 통해 서버로 전달, 서버와 클라이언트 양측에서 처리

 

* ex) 엔티티/블럭/아이템을 보여줌,

플레이어 자신의 행동 제어(일부)

스레드(Thread)

Server Thread

(* 서버 프로그램에서 Server Thread만 존재)

Client Thread

주요 클래스

관리자: MinecraftServer

월드: WorldServer

관리자: Minecraft

월드: WorldClient

 

한편 서버도 서버 프로그램에서 작동되느냐, 클라이언트와 같이 작동되느냐에 따라 달라지는데요,

 

각각을 Integrated Server, Dedicated Server라 합니다.

 

이들은 다음과 같은 차이점을 가집니다.

 

차이점

Integrated Server

Dedicated Server

위치

Minecraft.exe에서 월드가 열려 있을 때 활성

(싱글플레이, LAN 서버)

MinecraftServer.jar 와 같은 서버 프로그램

(실행시 항상 활성)

클라이언트와의 관계

동시에 같이 존재 (Thread를 달리함)

같이 존재하지 않음

세이브 데이터 위치

프로파일 위치(보통 .minecraft)

서버 프로그램 위치

(추가 예정)

  

 

그러니까 싱글플레이, LAN 서버, 멀티플레이 각각에서 다음과 같이 존재합니다.

 

서버측

클라이언트측

싱글플레이(SSP)

Integrated Server

O

LAN서버

Integrated Server

(LAN으로 플레이어 입장 가능)

O

멀티플레이(SMP)

Dedicated Server

(Minecraftserver.exe)

(Minecraft.exe)

 

(참고로, 한 프로그램 내에서 돌아가는 서버와 클라이언트조차도 서로 통신을 합니다. 일관성을 유지하기 위해서죠)

 

 

다시 모드 제작으로 돌아가봅시다.

 

만약 마인크래프트가 싱글 혹은 LAN 플레이만 지원하거나, 아니면 멀티플레이만 지원했다면,

 

모드를 제작할 때에도 서버와 클라이언트, 즉 Server Side와 Client Side의 구분만 잘 해주면 되었을 것입니다.

 

문제는 마크가 둘 다 지원한다는 데에 있습니다. 그에 따라 모드 제작에서도 Integrated Server와 Dedicated Server 환경이 모두 존재하게 됩니다.

 

그래도 모장과 포지 제작팀은 저 둘을 할 수 있는 만큼 비슷하게 만드려는 시도를 합니다.

 

하지만 클라이언트가 같이 돌아가는 경우와 그렇지 않은 경우는 차이가 날 수밖에 없었습니다.

 

결국 결론은, 모드 제작에서도 이를 고려해주어야 한다는 겁니다. 그리고 이 부분에서 항상 많은 실수와 오류가 발생하죠.

 

그나마 다행인 점은 고려해주어야 하는 경우가 그리 많지는 않다는 것입니다.

 

 

포지 팀도 이런 애로사항을 잘 알고 있었고, 그러한 경우들을 통합적으로 관리하기 위한 도구를 하나 창조하였습니다.

 

그 도구가 바로 '프록시(Proxy)'입니다!

 

주의: 여기서의 Proxy는 넷상의 프록시 서버와는 다른 개념입니다!

 

프록시는, 일반 마인크래프트 프로그램(Minecraft.exe)과 마인크래프트 서버 프로그램(주로 Minecraft_Server.exe) 를 구분해서,

 

두 경우에 서로 다른 코드를 동작하도록 해주는 도구입니다. (정확히는 각 경우에 대해 작동하는 클래스를 바꾸어 줍니다.)

 

이러한 프록시는 주로 다음의 문제를 해결하기 위해 쓰입니다.

 

# Dedicated Server에서도 클라이언트용 소스가 남아있는 문제

 

일반적인 모드는 클라이언트와 서버 양측 모두를 제어합니다. 그런데 이 경우, Dedicated Server에서 치명적인 문제가 생길 수밖에 없습니다.

 

모드 파일은 하나이지 둘이 아니다보니, 이것으로 Dedicated Server와 Integrated Server 모두를 돌려야 한다는 데에서 문제가 생깁니다.

 

Integrated Server 환경에서는 서버와 클라이언트가 모두 필요하니, 모드 파일에서도 둘 모두를 지원해야 하는 반면,

 

Dedicated Server에서는 마인크래프트 서버만 있고 클라이언트가 없기 때문에 사용되지 않는 클라이언트 부분은 무용지물이 됩니다.

 

그 뿐만 아니라, 클라이언트용 마인크래프트 코드가 없기 때문에 심지어 크래시를 터뜨리게 되죠.

 

바로 여기서 프록시가 해결사로 등장합니다.

 

프록시는 일반 마인크래프트 프로그램과 마인크래프트 서버 프로그램을 구분해준다고 했었죠?

 

여기서 일반 마인크래프트 프로그램은 Integrated Server 환경이고, 마인크래프트 서버 프로그램은 Dedicated Server 환경인 것을 생각하면, 답이 나옵니다.

 

즉 프록시는 각각의 환경에 대해 실행되는 코드를 다르게 해주는 역할을 하는 것입니다.

 

더 자세하게는, 클라이언트에서만 실행되어야 하는 코드 (ex. 렌더링 관련)의 경우에 이 위치에 놓이게 됩니다.

 

이제 코드를 통해 직접 그 사용법을 알아보도록 합시다.

 

 

갑자기 많은 코드가 추가되었죠? 하나 하나 설명을 해 드리겠습니다.

 

@Instance

모드 (기반) 클래스의 인스턴스를 지정해 주는 어노테이션입니다. 이렇게 지정된 전역변수는 그 모드 클래스의 인스턴스로서 기능하게 되죠.

항상 이 인스턴스를 이용하여 모드 클래스에 접근하면 됩니다. 이렇게 하지 않고 인스턴스를

 

@Instance(value=MODID)

public static (모드 클래스) instance;

 

이런 식으로 선언하시면 됩니다. 저의 경우 모드 아이디가 "abrtutorial" 이므로 이 값을 넣었습니다. 이런 식으로 넣어도 되지만

AbrTutorial.MODID 이런 식으로 전역변수로 선언했던 모드 아이디를 대입해도 됩니다.

 

 

@SidedProxy

이 글에서 계속 이야기했던, 바로 그 프록시를 제시해 주는 어노테이션입니다. 다음과 같이 선언합니다.

 

@SidedProxy(clientSide="(클라이언트 프록시 클래스의 경로)", serverSide="(서버 프록시 클래스의 경로)")

public static (프록시 클래스) proxy;

 

여기서, '클래스의 경로'에 들어가는 것은 클래스가 위치한 패키지까지 모두 표시한 클래스의 이름을 나타내는 문자열입니다.

영어로는 Fully Qualified Name 이라고도 합니다.

 

또한, 클라이언트 프록시와 서버 프록시는 사이드 자체와는 관련이 없음을 주의하셔야 합니다.

클라이언트 프록시는 일반 마인크래프트용, 즉 Integrated Server에서 작동하는 프록시입니다.

반면 서버 프록시는 마인크래프트 서버용입니다. Dedicated Server에서 작동하는 프록시이죠.

 

어쨌든, 이렇게 프록시는 기본적으로 클래스로 구현됩니다.

그리고 환경에 따라 프록시 인스턴스에 다른 프록시 클래스가 적용되는 것이죠.

 

원칙적으로는 프록시의 기반 클래스로 BaseProxy를 두고, 클라 프록시를 ClientProxy, 서버 프록시를 ServerProxy로 두어야 하지만,

일반적으로는 서버 프록시를 따로 둘 필요가 없기 때문에 이를 CommonProxy로 두고,

클라 프록시를 ClientProxy로 두어 CommonProxy를 상속받게 됩니다.

 

그래서 저도 마찬가지로 abr.tutorial 패키지에 CommonProxy와 ClientProxy의 두 프록시 클래스를 만들고, 저렇게 사용한 것입니다.

 

정말 특별한 모드를 제작하시는 것이 아니라면, 저처럼 그대로 따라하셔도 거의 문제가 없습니다.

 

 

그러면 이제 정말로 프록시를 쓰는 법을 알려드리도록 하겠습니다. 직접 써 보면 더 이해가 잘되겠죠?

 

먼저 어떻게 써야 하는지를 생각해 봅시다.

프록시의 가장 중요한 용도는, 클라이언트에서는 꼭 필요하지만 서버에서는 작동하지 않는 코드를 프록시에 위치시키는 것이라고 했었죠?

 

그 예를 살펴보자면, 우선적으로 렌더링이 있습니다.

 

렌더링이란, 프로그래밍에서의 '그리기' 에 해당하는 개념인데, 바로 우리가 보는 화면을 그려주는 것이죠.

 

우리도 우리가 만든 블럭이나 아이템, 몹 등을 직접 그려줘야 할 일이 있을지도 모릅니다.

 

그러기 위해서는 렌더링을 도맡아 해줄 '렌더러(Renderer)' 내지 '렌더링 핸들러(Rendering Handler)' 객체가 필요하게 되고,

이 객체들을 포지에 등록(Register) 해줄 필요도 생기죠.

 

문제는, 역시 이들이 클라이언트에서만 작동한다는 것입니다. 그러므로 등록(레지스터) 작업도 당연히 프록시에서 이루어져야 하죠.

 

그러면 이 부분을 개략적으로 프록시로 구현해보기로 합시다. 우선 프록시에 렌더러들을 등록할 메서드를 하나 새로 만들어보죠.

 

CommonProxy.java:

 

ClientProxy.java:

 

여기서 CommonProxy는 마크 서버용, ClientProxy는 일반 마크용이므로,

 

렌더러 등록(레지스터) 은 당연히 ClientProxy에서만 하게 될겁니다.

 

이제 다음과 같이 모드 클래스의 init 메서드로 하여금 이 메서드를 호출하게 하면 됩니다.

 

물론 이렇게 하면 단순히 init 메서드에서 등록해준 경우와 동일하겠지만, 서버에서 크래시를 내지는 않겠죠!

 

 

여기까지 사이드 개념과 Integrated/Dedicated 환경 개념을 알아보고, 프록시를 이용하는 법을 알아보았습니다.

 

다음 강좌에서는, 본격적으로 블럭을 만들어 보도록 하겠습니다!

Posted by Abastro
강좌/Minecraft Mod 제작2015. 11. 4. 16:02

강의 환경 : 마인크래프트 1.7 이상

강의 목표 :

1. 모드를 언어로 현지화할 있다.

 

이 강좌에서는 모드를 영문, 한글과 같은 언어로 현지화하는 방법을 알아보도록 합시다.

 

이 강좌는 기본적으로 자신이 새로 만든 모드에 적용되며,

 

이미 있던 모드를 현지화하는 경우에도 적용할 수 있습니다.

 

1. Lang 파일 만들기

 

현지화를 위해서는 우선 lang 파일을 만드셔야 합니다.

 

새로 만드신 모드에 적용하는 경우에는 프로젝트 폴더에서src\main\resources\assets\(모드 아이디) 폴더로 이동하신 후,

 

여기에 lang 폴더를 만드시면 됩니다.

 

이미 있는 모드를 현지화하고 싶으신 경우에는resources\assets\(모드 아이디)\lang폴더로 이동하세요.

 

이제 lang 파일을 이용해 한국어와 국제 표준어인 영어로 각각 현지화를 해 보기로 합시다.

 

저 위치에 en_US.lang 파일과 ko_KR.lang 파일을 만들어 주세요.

(이미 있는 모드를 현지화할 경우에는 이미 있는 en_US.lang 파일을 복사하여 ko_KR.lang 파일을 만드시면 됩니다)

 

 

저렇게 말입니다.

 

영어부터 우선 작업해 봅시다. en_US.lang을 메모장으로 열어주세요.

(이미 있던 모드의 경우, en_US.lang 파일은 이미 작성이 되어 있을 테니 한국어 현지화 부분까지 넘어가세요)

 

블럭과 아이템을 현지화하려면, tile.tutorial.name, item.tutorialtem.name 같은 것 대신 현지화된 이름을 주어야 하겠죠?

 

그러니까 다음과 같이, 마치 대입하듯이 = 앞에 현지화 전 이름을, 뒤에 현지화한 후의 이름을 적으시면 됩니다.

 

 

여기서 비현지화 이름을 구하는 방법은 몇 가지가 있습니다.

1. 현지화 전에 eclipse에서 마인크래프트를 실행하신 후 블록/아이템에 대해 뜨는 이름을 찾습니다.

2. 그냥 블록은 tile.(블록 비현지화 이름).name, 아이템은 item.(아이템 비현지화 이름).name입니다. (…)

이때 비현지화 이름은setBlockName/setItemName 혹은 setUnlocalizedName으로 설정했던 이름입니다.

 

이제 ko_KR.lang파일도 작성해 주어야겠죠?

 

역시 = 앞에는 현지화 전 이름, = 뒤에는 한글로 현지화한 후의 이름을 써주세요.

(이미 있던 모드의 경우에는 영어로 현지화된 이름을 한글로 번역하시면 됩니다.

또 블록/아이템만 현지화된 건 아닐 테니. 알아서 잘 번역하세요;)

 

저의 경우 다음과 같이 작성했습니다.

 

 

이때, 제일 처음 줄은 빈칸으로 놓아야 제대로 해석이 될 겁니다.

 

마지막으로 저장할 때 주의점이 있습니다.

 

인코딩을 UTF-8로 변환해 주어야 한다는 것이죠. (한글에만 해당합니다)

 

어떻게 UTF-8로 저장하냐고요? 우선 다른 이름으로 저장으로 가주세요.

 

 

여기서 인코딩이 아마 ANSI일 텐데, UTF-8로 바꾸시면 됩니다.

 

한번만 이렇게 인코딩을 바꿔놓으면 계속 유지되기 때문에 다시 하실 필요는 없습니다.

 

그렇게 저장을 하면, 현지화가 끝났습니다! 한번 영어부터 확인해 볼까요?

 

 

 

제대로 되었군요!

 

이제 한국어로 확인해 봅시다.

 

 

그럼 이렇게 되었다는 것을 확인하실 수 있습니다!

 

 

 

이제 드디어 예쁜 현지화된 블럭, 아이템 이름을 보실 수 있는 겁니다!

(있는 모드를 현지화하는 경우 여기부터 읽지 않으셔도 됩니다.)

 

 

2. 커스텀 문자열 현지화하기

(선행강좌: 아직 작성되지 않음(…))

 

실제로 현지화가 필요한 것은 블럭, 아이템 이름 뿐만이 아니죠. 알림 메시지 등도 현지화가 필요합니다.

 

여기서는 이러한 커스텀 문자열을 현지화하는 방법을 알아보도록 하겠습니다.

 

튜토리얼 블럭을 우클릭했을 때, 현지화된 문자열이 뜨도록 하는 예제를 통해 알아보도록 합시다.

 

우클릭했을 때는 onBlockActivated 메서드가 호출되니까, 이 메서드를 상속받고 다음과 같이 작성해주면 됩니다.

 

(잘린 줄은 다음과 같은 내용입니다:

player.addChatMessage(new ChatComponentText(StatCollector.translateToLocal("command.activate")));

)

 

여기서, 1개의 조건문과 3개의 메서드를 호출했음을 알 수 있습니다. 각각에 대해 설명하자면,

 

0. world.isRemote: 클라이언트 월드에 대해 true, 서버 월드에 대해 false 값을 갖고 있습니다.

onBlockActivated는 CLIENT side, SERVER side 양쪽 모두에서 호출되기 때문에,

메시지를 1번만 보내기 위해 체크를 하였습니다.

1. player.addChatMessage(IChatComponent comp) : 플레이어에게 알림 메시지를 보냅니다.

2. new ChatComponentText(String text) : String 텍스트로 구성된 채팅 메시지 컴포넌트를 만듭니다.

3. StatCollector.translateToLocal(String unloctext) : 해당 문자열을 현지화시킵니다!

 

그러니까, 간단히 StatCollector.translateToLocal을 통해 현지화를 해주면 되는 겁니다.

 

물론 lang 파일에 command.activate를 현지화하는 줄을 넣어야겠죠?

 

 

 

이런 식으로 작성한 다음 저장해 주시면..!

 

영어로 설정한 경우,

 

 

저렇게 뜨고요.

 

한국어로 설정하면

 

 

이렇게 뜨게 됩니다!

 

여기까지 간단하게 커스텀 문자열을 현지화하는 방법을 알아보았습니다.

 

정리하자면,

 

StatCollector.translateToLocal(String unloctext)

 

를 사용하면 된다는 겁니다. 물론 unloctext는 command.activate나 abs.tutorial.call 같은 형식으로 해놓고,

 

lang 파일에서 command.activate=(현지화된 문자열) 으로 하면 되는 겁니다.

 

그런데 만약 %s, %d 같은 것으로 문자열이나 수를 입력하고 싶다면 어떻게 해야 할까요?

 

이때는 대신 StatCollector.translateToLocalFormatted(String unloctext, Object... obj)

 

를 사용하시면 됩니다! 여기서, unloctext는 command.activate 같은 형식으로 하시고,

 

lang 파일에서 현지화된 문자열을 넣는 위치에 적당히 %s, %d를 배치해 주시면 되는 거죠.

 

예를 들자면 lang 파일에 abs.tutorial.call=Calling %s...

 

이런 식으로 해 놓고 translateToLocalFormatted의 2번째 인자에 String을 넣어도 되는 것이죠.

 

 

여기까지 lang 파일을 이용한 모드 현지화 강좌였습니다!

Posted by Abastro
강좌/Minecraft Mod 제작2015. 11. 4. 08:03

강의 환경 : forge-1.7.10-10.13.0.1160-1.7.10

선행 과정 : [1.7.10] 모드기반제작

강의 목표 :

1. 기본적인 블록을 제작할 있다.

 

이 강좌에서는 기본적인 블록을 제작하는 방법을 알아보도록 하겠습니다.

 

이를 통해 블록 타입에 해당하는 객체를 만들고, 마인크래프트에 등록해주는 작업을 하게 될 것입니다.

 

 

그럼, 우선 블록의 성질을 결정하게 될 클래스를 만들어 봅시다.

 

보통 블록, 아이템 각각에 대해 block, item과 같은 패키지를 만들어 관리하는데,

 

저도 이 관례를 따라 abr.tutorial.block에 블록 클래스들을 두기로 하였습니다.

 

굳이 이를 따르실 필요는 없습니다.

 

이제 Block을 상속한 블록 클래스를 만들면 됩니다. 저는 BlockTutorial라는 클래스를 만들었습니다.

 

그럼 이렇게 컴파일 오류가 발생합니다. 자동으로 해결해 보면,

 

 

여기서 Material이 생성자의 인자로 들어가야 한다는 사실을 알 수 있습니다.

 

이렇게 블록에는 항상 Material을 지정해 주어야 하는데,

 

여기서 Material은 블록의 재질을 나타내며, 공기/액체/고체 여부와 블록을 밟았을 때의 소리 등을 결정합니다.

 

보통 블록은 고정된 재질을 가지므로 다음과 같이 super에 원하는 재질을 넣어주시면 됩니다.

 

저는 적당히 돌(Material.rock) 로 하기로 결정했습니다.

 

다른 재질을 원하신다면, Material의 전역변수 중에서 찾으시면 됩니다.

 

 

이제 생성자에서 블록의 몇 가지 성질을 지정할 수 있습니다.

 

기본적으로 Block#setBlockName(String name)으로 블록의 이름을 설정할 수 있고,

 

Block#setCreativeTab(CreativeTabs tab)으로 크리에이티브 탭을 설정할 수 있습니다.

 

여기서 CreativeTabs의 인자로 넣을 탭 객체는 보통 CreativeTabs의 전역변수 중에서 찾아볼 수 있습니다.

 

저는 이름은 tutorial로, 크리에이티브 탭은 기타(Miscellaneous) 탭에 해당하는 CreativeTabs.tabMisc를 쓰기로 결정했습니다.

 

 

이제 텍스쳐를 할당해 보도록 합시다.

 

여기서는 간단히 하나의 텍스처를 모든 면에 대해 적용하는 방법만 알아보고,

 

각 면에 따라 다른 텍스처를 이용하는 방법은 추후에 강좌를 올리도록 하겠습니다.

 

우이를 위해서, Block#setBlockTextureName을 이용해 텍스처 이름을 설정해 주되,

 

반드시 모드ID (MODID) 뒤에 :를 붙인 후 텍스처 이름을 써 주셔야 합니다.

 

예를 들어 텍스처 이름이 tutorial(.png)이면, 다음과 같이 하시면 됩니다.

 

 

이제 텍스처를 위치시켜 봅시다.

 

(프로젝트 위치)/src/main/resources/assets/(MODID)/texture/blocks 위치에 지정한 이름의 png 텍스처 파일을 위치시키면 됩니다.

 

저의 경우 다음과 같습니다.

 

 

여기까지 하면 기본적인 블록의 형태는 완성이 된 것입니다.

 

이제 추가적인 성질들을 설정해 봅시다.

 

블록에는 다음과 같은 성질들이 있습니다.

 

인자

역할

설정 방법

경도

(Hardness)

float

블록을 캘 때 걸리는 시간을 결정합니다.

Block#setHardness

나무: 2, 흑요석: 20

위키 링크(영어)

폭발 저항 강도

(Resistance)

float

블록의 폭발 저항 강도를 결정합니다.

Block#setResistance

나무: 15, 흑요석: 6,000

위키 링크(영어)

스텝 소리

(StepSound)

SoundType

블록 위를 걸어갈 때 나는 소리를 설정합니다.

Block#setStepSound

대부분 Block 클래스에 전역 변수로 설정

돌: #soundTypeStone

나무: #soundTypeWood

캐는 도구 설정

(HarvestLevel)

String toolclass, int level

블록을 캘 때 필요한 도구와 그 레벨을 결정합니다.

Block#setHarvestLevel

Toolclass: 곡괭이 "pickaxe", 삽 "shovel", 도끼 "axe";

level: Wood: 0, Stone: 1

Iron: 2, Diamond: 3

 

저는 적당한 강도에 돌 소리가 나며 돌 곡괭이 이상으로 캘 수 있도록 다음과 같이 설정하였습니다.

 

 

마지막으로 이렇게 구성한 블록을 등록해 줄 차례입니다.

 

preInit에서 블록의 인스턴스를 다음과 같이 만들어 등록해 주시면 됩니다. (저번에도 설명했지만 반드시 preInit이어야 합니다!)

 

GameRegistry#registerBlock(Block block, String id)를 이용해 간편히 등록할 수 있습니다.

 

저의 경우 다음과 같이 되었지요.

 

 

* Block#getUnlocalizedName()을 이용하는 실수는 하지 마시길 바랍니다.

저는 실수로 넣었지만, tile.tutorial같은 이상한 ID로 등록하는 바람에 버그가 발생하는 것을 원치 않으신다면

그냥 직접 타이핑하시는 것을 추천드립니다.)

 

이때, 반드시 클래스가 아닌 객체 형태로 등록해야 합니다.

 

블록 타입을 나타내는 것은 블록 클래스가 아니라 객체이기 때문입니다.

 

또한 이 객체는 나중에 이용하실 일이 많기 때문에, 미리 저장해 두시는 것을 추천합니다.

 

 

이제 우리의 새로운 블록이 추가되었는지 확인해 봅시다.

 

 

저렇게 잘 추가되었음을 볼 수 있습니다.

 

(이름이 tile.tutorial.name인 것은 아직 현지화 단계를 거치지 않았기 때문입니다.

현지화 강좌는 이곳에서 확인해 보실 수 있습니다!)

 

여기까지 기본적인 블록을 제작해 보았습니다.

 

다음 강좌에서는 메타데이터에 대해 알아보고 이를 다루는 법에 대해 알아보도록 하겠습니다!

Posted by Abastro
강좌/Minecraft Mod 제작2015. 10. 28. 20:42

 

강의 환경 : forge-1.7.10-10.13.0.1160-1.7.10

강의 목표 :

  1. 마인크래프트가 실행될 발생하는 FML 기본 이벤트들을 이해할 있다.

 

이번 강좌에서는 FML 기본 이벤트들에 대해 알아보겠습니다.

 

저번 '모드 기반 제작' 강좌에서,

  • FMLPreInitializationEvent
  • FMLInitializationEvent
  • FMLPostInitializationEvent

를 배웠었죠?

 

사실 이들 말고도 이런 종류의 이벤트들이 더 있습니다.

 

이들은 모두 같은 방식으로 이용할 수 있습니다:

 

  1. 모드 기반 클래스에 @EventHandler가 붙은 메소드를 통해 이벤트를 받습니다.
  2. 이벤트 인자를 통해 받을 이벤트의 종류를 결정할 수 있습니다.
  3. 이벤트 인자 내부 필드/메소드들을 통해 이벤트와 관련된 여러 작업을 할 수 있습니다.

 

우선 이미 보았던 FML 기본 이벤트들을 더 자세히 살펴봅시다.

 

1.시작시 발동되는FML 기본 이벤트들

 

이벤트

시기

주요 용도

클라이언트

서버

FMLPreInitializationEvent

모드 로딩 시 1순위

* 모드 초기화 작업

*아이템/블록/엔티티 등록

FMLInitializationEvent

모드 로딩 시2순위

*PreInit 다음에 수행되어야 하는 초기화 작업

*조합법 등의 작업 등록

*모드간의 호환성 작업

(초기 수정)

FMLPostInitializationEvent

모드 로딩 시 3순위

*모드간의 호환성 작업

(후기 수정)

 

이 중FMLPreInitializationEvent이벤트만이 (유용한) 메소드들을 지니고 있습니다.

 

이벤트 / 메소드 이름

형태

용도

FML-

Pre-

Initialization-

Event

getSourceFile

File …()

소스 파일의 경로를 가져옵니다.

getModMetadata

ModMetadata …()

모드 ID, 이름 등의 정보를 담고 있는 객체를 가져옵니다.

getModConfigurationDirectory 

File …()

모드 컨피그들이 들어있는 경로를 가져옵니다. ((마크 위치)\config)

getSuggestedConfigurationFile 

File …()

해당 모드에 대해 추천되는 컨피그 파일 경로를 제공합니다.

getAsmData

ASMDataTable …()

해당 모드에 대한 ASM 데이터를 가져옵니다.

getVersionProperties 

Properties …()

해당 모드의 버전 속성을 가져옵니다.

getModLog 

Logger …()

해당 모드를 위한 Logger를 가져옵니다.

(디버깅 목적으로 유용합니다)

 

특히 getModLog, getModContigurationDirectory/getSuggestedConfigurationFile은 각각 디버깅, 컨피그 부분에서

 

유용하게 쓸 메소드들이니 꼭 기억해 두세요!

 

 

2.상태에 관련된FML 기본 이벤트들

 

이제 상태에 관련된 FML 기본 이벤트들을 알아봅시다.

 

이들은 주로 모드를 불러오거나, 서버가 시작되거나 끝날 때 발동됩니다.

 

이들 대부분은 상당히 중요하며 요긴하게 쓰이는 이벤트들이므로 꼭 기억해 두세요.

 

(FMLInitializationEvent 등지도 상태 관련 이벤트이지만, 편의상 따로 두었습니다)

 

이벤트

시기

주요 용도

클라이언트

서버

FMLConstructionEvent

모드 로딩 전

(모드 기반 클래스가 처음 로딩되었을 때)

모드 기반 클래스 로딩

FMLLoadCompleteEvent

모드 로딩 완료 후

모든 로딩이 완료되었을 때 작업을 수행합니다.

(PostInit에 등록을 하는 모드들을 호환시키기 위해 필요합니다..)

FMLServerAboutToStartEvent

월드 시작시

1순위

서버 세팅 로딩 후

(PostInit후)

서버 세팅 로딩

FMLServerStartingEvent

월드 시작시

2순위

서버 월드 로딩 후

월드 관련 작업

서버 커맨드 등록

FMLServerStartedEvent

월드 시작시

3순위

서버가

시작된 직후

서버 최종 세팅

FMLServerStoppingEvent

월드

종료시 1순위

서버 종료시 1순위

데이터 저장, 백업 등

FMLServerStoppedEvent

월드 종료시 2순위

서버 종료시 2순위

데이터 저장, 백업 등

 

(볼드체로 쓴 이벤트들이 중요합니다!)

 

여기서 유용한 메소드는 단 3개입니다.

 

FMLServerAboutToStartEvent or FMLServerStartingEvent #getServer(): 서버를 관리하는 객체인 MinecraftServer의 인스턴스를 줍니다.

 

FMLServerStartingEvent #registerServerCommand(ICommand command): 서버 커맨드를 등록합니다. (커맨드를 등록하는 유일한 방법!)

 

 

3.기타FML 기본 이벤트들

 

기타로 다음과 같은 이벤트들이 추가로 있습니다.

 

이벤트

시기

주요 용도

클라이언트

서버

FMLFingerprintViolationEvent 

모드 파일의 무단 변경이 감지되었을 때

보안용

(*Fingerprint(지문)를 지원하는 모드에 대해서만 발동됩니다)

FMLModDisabledEvent 

모드를 비활성화했을 때

(*현재 이 버전에선 작동하지 않습니다)

모드 비활성화 지원

FMLMissingMappingsEvent

월드에 저장된String ID에 해당하는 블록/아이템이 없을 때

1. 업데이트 시에 아이템/블록 ID를 바꾼 경우

2. ID가 바뀌었을 때 경고를 하고 싶은 경우

FMLModIdMappingEvent

월드에 저장된 int ID가 다른 int ID로 해석될 때

주로 1.6->1.7 업데이트 시 ID 시스템의 변화로 인한 문제를 감지하기 위함

IMCEvent 

FMLPreInit…과 FMLInit… 사이

모드간 통신 (즉 호환성을 위함)

 

1. FMLFingerPrintViolationEvent

모드 파일의 무단 변경이 감지되었을 때 발동되는 이 이벤트는 4개의 public 멤버변수를 지닙니다.

- Boolean isDirectory: 변경된 파일이 Directory인지 확인

- Set<String> fingerprints: 받아들인 파일 지문(Fingerprint)의 목록

- File source: 문제가 발생한 소스

- String expectedFingerprint: 예상한 파일 지문

이 이벤트를 이용하기 위해서는,

저번 강좌에 사용했던 @Mod 어노테이션의 certificateFingerprint필드에

예상되는 지문이 반드시 지정되어 있어야 합니다.

(꼭 필요하면 사용하시되 과신을 하지 마세요)

 

2. FMLModDisabledEvent

모드가 불활성화될 때 발동되(어야 하)는 이벤트입니다. ModList Gui의 Disable 버튼과 관련이 있는듯 하지만,

현재 버전에서는 아직 이용할 수 없습니다.

 

3. FMLMissingMappingEvent

월드에 저장된 ID에 해당하는 블록/아이템이 없을 때 발동되는 이벤트입니다. (이때 ID는 String입니다)

List<MissingMapping> get()을 통해 자신의 모드에 대한 ID들을,

List<MissingMapping> getAll()을 통해 자신의 모드에 대한 들을 가져올 수 있습니다.

 

이 각각의 MissingMapping들은 String 형태의 ID와 int 형태의 ID를 지니고 있는데,

이들을 확인한 후 ignore/ warn/ fail을 통해 무시/경고/실패를 알리거나,

Remap을 통해 알고 있는 블록/아이템들을 사용하도록 지정할 수 있습니다.

 

4. FMLModIdMappingEvent

1.6에서 1.7로 업데이트되면서 ID 시스템이 바뀌게 되었는데, 이로 인해 발생할 수 있는 오류를 감지하기 위한 이벤트입니다.

(1.6까지 항상 아이템/블록의 식별자는 정수였으나, 1.7부터 String으로 바뀌었습니다.

이로 인해 아이템/블록 저장/로딩 방식도 약간 바뀌면서 문제가 발생합니다)

 

이 이벤트에는 다음과 같은 멤버변수 하나가 있습니다.

ImmutableList<ModRemapping> remappedIds;

ModRemapping은 월드에 저장된 int id와, 바꿀 int id를 함께 지니고 있으며

remapTarget으로부터 블록인지 아이템인지를 알 수 있고,

tag로부터 블록 혹은 아이템의 이름을 알 수 있습니다.

이 이벤트를 통해서는 감지만 가능하며 어떤 것도 수정할 수 없습니다.

 

 

5. IMCEvent

마지막의 IMCEvent는 Forge가 모드간 통신을 가능하게 해준 Inter Mod Commons기능의 일부입니다.

이 부분은 언젠가 기회가 되면 따로 강좌하기로 하겠습니다.

 

 

이상으로 FML 기본 이벤트들에 대한 강좌를 마치도록 하겠습니다.

Posted by Abastro
강좌/Minecraft Mod 제작2015. 10. 6. 20:08

강의 환경 : forge-1.7.10-10.13.0.1160-1.7.10

강의 목표 :

1. 모드의 기반 클래스를 작성할 있다.

2. Mod Name, ID, Version 같은 모드 정보를 이해한다.

3. PreInit, Init, PostInit이벤트 메소드를 이용할 있다.

 

이 강좌에서는 모드의 기반이 되는 클래스를 만들어 보도록 하겠습니다.

 

우선, 프로젝트를 열고 Package Explorer 탭을 봐 주세요.

 

src/main/java 디렉토리를 펼쳐주시면, 다음 사진과 같이 examplemod가 나올 겁니다.

 

 

저 ExampleMod는 일종의 예시 모드인데,

 

기본적인 모드는 어떻게 구성되어야 하는지를 보여주고 있습니다.

 

이 모드는 아무 일도 하지 않습니다. 오직 모드의 기반만 포함하고 있는 예제이기 때문이죠.

    

그렇기에 이번 강좌의 목적에 잘 부합하기도 합니다.

 

우선 이 모드를 구성하는 유일한 소스 파일인 ExampleMod.java를 살펴보면서,

 

모드를 어떻게 구성해 나가야 하는지 살펴보도록 합시다.

 

 

위 사진은 ExampleMod.java를 열었을 때 나오는 화면입니다.

 

그렇게 많은 내용이 있지는 않지만, 일반적인 자바 프로그래밍을 해오신 분들이라면 잘 이해가 가지 않는 부분이 몇 군데 있을 겁니다.

 

그리고 그 이유는 아마 포지가 @Mod나 @EventHandler와 같은 Annotation을 중요하게 많이 활용하기 때문일 것입니다.

 

(잘 모르시는 분은 다음 사진까지 넘어가셔도 됩니다)

 

일반적으로는 Annotation은 드물게 활용되는 편이며 중심적인 역할을 맡는 경우는 드물고, 그나마 주석과 비슷한 용도로만 사용되는 경우가 흔한데,

 

포지에서는 모드의 기반이 되는 클래스에는 물론 이제는 포지의 핵심이 된 이벤트 체계도 Annotation을 중심으로 구성되어 있습니다.

 

사실 저도 왜 저렇게 되었는지 이해가 잘 가지는 않습니다만..

 

아마 모드 제작자에게 인터페이스 등을 상속하지 않을 자유를 주기 위한 것이라 생각됩니다. 사실 그러한 상속 작업이 번거롭기는 하지요.

 

한편 부작용으로, 처음 모드를 제작하는 분들은 어떻게 시작을 해야 하는지 알기가 어렵고,

 

모드 버전을 업데이트할 때에도 빨간 줄의 오류만 보게 되며 실제로 어떤 부분을 바꾸어야 하는지를 알기 어렵게 됩니다.

 

사실 그런 이유로 ExampleMod.java라는 파일이 등장한 것으로 보입니다만, 여기서 사설은 그만두겠습니다.

 

 

어쨌든, 위 사진의 내용으로 다시 돌아가서 살펴보겠습니다.

 

위 코드를 분석해 보면, 중요한 몇 부분을 발견할 수 있습니다.

 

1. @Mod

이 어노테이션은 모드 (기반) 클래스를 표시해주는 역할을 하며,

 

주로 @Mod(modid = "examplemod", name="ExampleMod", version="1.0.0") 이런 식으로 작성하게 됩니다.

 

여기서 modid, name, version과 같은 인자들은 필수적으로 지정해 주어야 합니다.

이들은 다음 표와 같은 의미를 갖습니다.

인자 이름

자료형

의미 및 용법

modid

String

모드의 ID(식별자) 입니다. 모드마다 각기 달라야 합니다.

name

String

Mods창을 열면 표시되는 모드의 이름입니다.

version

String

모드의 버전입니다. 업데이트할 때마다 바꾸어주어야 합니다.

 

이 외에도 다음과 같은 인자들이 있습니다. (필수적인 것은 아닙니다)

인자 이름

자료형

의미 및 용법

dependencies

String

어떤 모드에 필요한 다른 모드들을 지정하거나, 모드들의 로딩 순서를 지정합니다.

useMetadata

boolean

true로 지정될 경우, @Mod의 modid, name, version 등의 정보 대신 mcmod.info 에 지정된 모드 정보를 사용합니다.

acceptedMinecraftVersions

String

받아들일 마인크래프트 버전을 의미합니다.

acceptableRemoteVersions

String

클라이언트가 서버에 연결했을 때 받아들일 버전의 범위를 의미합니다.

acceptableSaveVersions

String

세이브 파일 형식이 호환되는 버전의 범위를의미합니다.

bukkitPlugin

String

이 모드를 위해 로딩할 플러그인을 지정합니다. 플러그인-모드 연계에 쓰이는 것으로 보입니다.

certificateFingerprint

String

이 모드 파일에 대한 지문을 지정합니다. 이를 통해 무단 변경된 모드의 이용을 막을 수 있습니다.

modLanguage

String

언어를 지정합니다. (적절한 ILanguageAdapter만 할당해 주면, 다른 언어로 작성하는 것도 가능합니다)

canBeDeactivated

boolean

모드가 disable될 수 있는지를 의미합니다만, 현재로서는 용도가 없는 것으로 보입니다.

guiFactory

String

Config Gui에 사용되는 IGuiFactory구현 클래스의 위치를 지정합니다.

customProperty

CustomProperty

커스텀 속성을 지정할 수 있습니다.

 

 

 

2. @EventHandler

이 어노테이션은 모드 클래스로 하여금 기본적인 이벤트들을 받을 수 있도록 해줍니다.

 

위의 예를 들어 설명하자면,

 

@EventHandler

public void init(FMLInitializationEvent event)

 

자바의 기본 원리대로라면, 당연히 저 init 함수는 절대로 호출될 수 없습니다.

 

하지만 실제로는 호출됩니다. 어떻게 그럴 수 있을까요?

 

사실 모드를 로딩할 때, 포지는 이미 모드 클래스들을 조사하고 그 인스턴스도 만들어 둔 상태입니다.

 

이때 FMLInitializationEvent가 발생하면, 포지는 각각의 모드 인스턴스에 대해 저 init 함수를 호출하는 것이지요.

 

특히 저 부분은 중요한 역할을 하는데, 바로 모드의 초기화 시점에서 호출되기 때문입니다.

 

즉 처음 모드가 실행될 때의 초기화는 모두 저 init 함수에서 하게 되죠.

 

저 예제 모드에서는, 모드 로딩 시에 콘솔 창에 흙 블록의 현지화되지 않은 이름을 출력하게 됩니다.

 

물론 아무리 예제 모드를 넣고 마크를 실행시켜도, 어떤 것도 발견하기 어려울 겁니다. 콘솔 창에만 기록되니까요.

 

* 기억해 두셔야 할 점이 하나 있는데, init 함수의 이름은 마음대로 바꿔도 되지만,

@EventHandler를 달고 FMLInitializationEvent를 인자로 가져야 한다는 규칙은 엄격히 지켜야 한다는 것입니다.

 

 

모드 기반 클래스를 제작하는 데에는 저 2개면 충분하다고 보시면 됩니다.

 

이제 우리는 새로운 모드를 창조해 보도록 합시다.

 

우선 작업할 패키지를 만들어야겠죠? 저는 abr.tutorial로 정했습니다.

 

 

여기서 자신만의 패키지를 만들어 주세요, 모드의 대부분의 구조가 그 안에 자리잡게 될 것입니다.

 

이를 제작하였다면, 이제 모드 기반 클래스를 만들 차례입니다.

 

저 패키지 안에 새로운 클래스를 만들어 주세요. 여러분이 만들 모드의 이름을 쓰는 것이 좋습니다. 꼭 그럴 필요는 없습니다만-

 

그래서 저는 다음과 같이 만들었습니다.

 

 

이제 모드 기반 클래스로서 제 구실을 하도록 만들어야겠죠? 아까 보았던 예제대로 구성을 해봅시다.

 

우선 @Mod를 붙여 주세요. 그럼 다음과 같이 됩니다.

 

 

(어노테이션의 인자에는 클래스에서 public static final로 선언한 변수의 값을 사용할 수 있습니다.)

 

위와 같이 모드 클래스에 public static final로 modid, name, version을 미리 선언해 둔 후, @Mod에서 참조하는 것을 추천합니다.

 

참고로 modid는 따로 쓸 일이 많기 때문에, 클래스에 public static final로 선언해 두는 것이 정말 도움이 됩니다.

 

 

그렇다면 이제 모드의 초기 구성을 위한 초기화 부분을 넣을 차례입니다.

 

아까 예제에서는 FMLInitializationEvent 하나밖에 없었지만,

 

일반적으로는 FMLPreInitializationEvent과 FMLPostInitializationEvent를 같이 사용합니다.

 

이 둘은 각각 FMLInitializationEvent 의 전과 후에 호출되며 각기 중요한 역할을 맡게 됩니다.

 

즉 우선 각각의 모드에 대해 FMLPreInitializationEvent가 모두 호출된 후, 역시 각 모드에 대해 FMLInitializationEvent가 호출되며, 이후 FMLPostInitializationEvent가 호출됩니다.

 

- FMLPreInitializationEvent에서는 주로 모드가 추가하는 블록과 아이템 등을 포지에 등록하게 됩니다.

* 모드 컨피그도 이곳에서 제공되지만, 그렇다고 이곳에서만 접근할 수 있는 것은 아닙니다.

- FMLInitializationEvent에서는 주로 모드 기본 세팅을 합니다. 이곳에서 레시피들을 등록하게 됩니다.

- FMLPostInitializationEvent에서는 주로 모드간의 호환과 관련된 일이 일어나게 됩니다.

 

이들에 대한 자세한 설명 역시 나중에 하도록 하겠습니다.

 

일반적으로는, 아래와 같이 작성해 주시면 됩니다.

 

 

여기까지 하셨다면, 이제 포지가 제공하는 기본 예제는 전혀 필요가 없습니다. 과감히 지워주도록 합시다.

 

(혹시라도 지금 안 지웠다가 여러분의 모드를 배포할 때까지 그대로 놓아두게 된다면,

나중에 사용자가 여러분의 모드를 받았을 때 ExampleMod라는 정체불명의(?) 모드가 같이 깔려있게 되는 불상사가 생길 수도 있습니다!)

 

여기까지 따라하셨다면, 이제 여러분은 모드 (기반) 클래스의 골격을 완성하신 겁니다.

 

… 프록시라는 한 가지 중요한 요소를 제외하고는 말이죠.

 

다음 강좌에서는 프록시에 대해 다뤄보도록 하겠습니다.

Posted by Abastro
강좌/Minecraft Mod 제작2015. 10. 6. 11:36

# 강좌는 Eclipse IDE 사용하며, Windows에서 설치하는 경우에 대해서만 설명합니다.

# 다른 OS 작업을 해야 한다면.. 문의를 주세요.

   

이번 강좌에서는 Forge 다운로드하고, 모드를 작성할 있도록 설정하는 법을 알려드리겠습니다.

   

먼저, 포지를 다운로드하기 위해서는 Minecraft Forge Forum 사이트로 가셔야 합니다.

   

가면 다음과 같은 창을 보실 있습니다.

   

   

여기서 Files 찾아 들어갑니다.

   

그러면 다음과 같은 창이 뜨지요.

   

   

그러면 저곳에 여러 버전들에 대한 Downloads 뜨는데,

   

우리는 1.7.10에서 작업할 것이므로 1.7.10 Recommended 받아줍시다.

   

(* Recommended 포지의 추천 버전으로서, 안정적인 것이 확인된 버전이고,

 Latest 어느 정도 안정적인 최신 버전으로서 Recommended보다는 부족한 편입니다.

   

 여기서는 Recommended 사용하지만, 최근에 업데이트된 새로운 Feature들을 사용하기 위해 Latest 사용하는 경우도

 많습니다.)

   

여기서 1.7.10-Recommended 찾아, 우측의 (Src) 눌러주시면 됩니다. (양심상 * 누르지 맙시다)

   

그런 다음 adf.ly에서 5초를 기다린 , 우측 상단에 나오는 다운받기를 클릭하여 다운받으시면 됩니다.

   

다운받은 파일을 원하는 곳에 압축을 풀어준 , 적당히 이름지어 줍시다. 주로 프로젝트와 관련된 이름을 지어주시는 것이 좋습니다.

   

저의 경우 다음과 같이 AbTutorial이라 지었습니다.

   

방금 만든 폴더에서, 모든 모드 제작 작업이 이루어지게 겁니다.

   

아직 폴더 안으로 들어가시면 안됩니다. 작업이 하나 남았거든요.

   

폴더를 Shift + 우클릭 해주세요.

   

   

, 여기서 명령 열기(W) 눌러 주시면 됩니다.

   

그럼 다음 명령 창이 뜹니다.

   

   

여기에 gradlew.bat setupDecompWorkspace eclipse 치면,

   

일련의 진행 상태 안내문들이 뜨면서 셋업을 시작할 것입니다.

   

* 여기서 주의할 점은, 인터넷이 연결되어 있어야 한다는 것입니다.

    인터넷 서버에서 다운로드해야 하는 파일들이 가지 있기 때문이죠.

   

   

사진은, 초기 진행 중에 뜨는 화면입니다. ( 과정에서 gradle이라는 프로젝트 설정 관리기를 준비합니다)

   

   

MCP 설정 중에 뜨는 화면입니다. MCP 팀을 설명하는 부분이 보이는군요.

   

   

MCP 설정이 끝나면 Forge ModLoader 설정이 진행됩니다.

   

   

그리고 시간을 두고 기다려 사진과 같이 Build Succesful 나오면, 정상적으로 완료된 것입니다.

(그렇지 않은 경우에는 문의해 주세요)

   

이러한 과정들은 아마 오래 걸릴 것이며, 시간을 두고 기다려야 것입니다.

   

그래도 예전보다는 상당히 빨라진 편입니다. (예전에는 40 이상 기다려야 하는 경우도 있을 정도였죠)

   

, 이렇게 하면 설정이 완료된 것입니다.

   

   

물론 상태에서 어떻게 eclipse 모드 작업을 해야 하는지, 막막할 겁니다.

   

우선 eclipse 열어 줍시다.

   

그럼 물론 다음과 같은 프로젝트 위치 선택 창이 뜨겠죠?

   

   

저기서 Browse 눌러, 우선 설치했던 프로젝트 위치를 찾아 줍시다. (저의 경우에는 AbTutorial입니다.)

   

   

사진과 같이 찾아주신 다음, 하위 폴더에서 eclipse 눌러 줍시다.

   

다음 사진과 같이 다음 확인 버튼을 눌러 주시면 됩니다.

   

   

이제 디렉토리에서 Eclipse 시작해 주시면, 다음과 같은 화면이 뜹니다.

   

   

위와 같이, Project Explorer 칸에 Minecraft 뜨면, 정상적으로 설정이 완료된 것입니다.

   

(역시 아니라면, 문의를 주시기 바랍니다.)

   

여기부터 이제, 모드 제작을 시작할 있습니다!

   

이번 강좌는 여기까지입니다. 다음 강좌에서는 모드의 기반을 만드는 일을 보도록 하겠습니다.

'강좌 > Minecraft Mod 제작' 카테고리의 다른 글

[1.7.10] 모드 현지화  (0) 2015.11.04
[1.7.10] 커스텀 블록 제작  (2) 2015.11.04
[1.7.10] FML 기본 이벤트들 (FML Lifecycle Events)  (0) 2015.10.28
[1.7.10] 모드 기반 제작  (0) 2015.10.06
Minecraft Forge 소개  (0) 2015.10.06
Posted by Abastro
강좌/Minecraft Mod 제작2015. 10. 6. 11:09

이번 포스팅에서는 모드 제작에 흔히 쓰이는 Forge 관해 소개해 보려 합니다.

모드 제작 강좌에 앞서, 혹시 MCP 모드로더를 이용한 모드 제작에 관해 질문하시는 분이 있을 같기도 하고

이들을 이해하는 것이 Minecraft Forge 대해 이해하는데 도움이 되기에,

우선 이들의 역사를 살펴보기로 하겠습니다.

 

1. MCP(Minecraft Coder Pack)

 

   

 

 먼저, 최초로 만들어진 모드 제작용 도구는 MCP였습니다.

 

MCP '마인크래프트 모드'라는 것을 가능하게 해준, 아주 혁신적인 도구였었죠.

 

도구는 난독화되어 있는 마인크래프트 소스를 해석하고, 주석을 달아 마인크래프트 소스를 수정할 있도록 해주었습니다.

 

MCP 출범함으로서, 마인크래프트의 자유도를 더욱 높이는 많은 모드들이 쏟아져나오기 시작하기도 했지요.

 

그런데 여기에는 문제가 하나 있었습니다.

 

MCP 이용해 만든 모드들은 마인크래프트 코드를 직접 고쳐 만들어졌기 때문에 대부분 서로 호환되지 않았고,

 

따라서 여러 모드들을 다운받아서 같이 수가 없었다는 것입니다. 다양한 컨텐츠를 한꺼번에 즐길 수가 없었죠.

 

그래서 문제를 해결하기 위해, MCP 기반 위에 2가지 플랫폼이 등장하게 되었는데,

 

그것이 바로 (리수가미의) 모드로더 마인크래프트 포지였습니다.

 

 

2. (리수가미의) 모드로더 (Risugami's Modloader)

 

 

( 사진은 리수가미의 모드로더와 상관이 없음을 알려드립니다)

 

MCP 이러한 결점으로 인하여, '모드 호환을 위한 모드' 만들어지기 시작했습니다.

 

그렇게 등장한 것이 Minecraft beta 1.2에서 등장한 리수가미의 모드로더입니다.

 

Risugami라는 모드 제작자 사람이 제작하였죠.

 

모드로더는, 설치된 모드들을 '로딩'함으로서 변경 사항들을 마인크래프트에 적용하는 방식으로 작동하는데,

 

따라서 그러한 모드들이 마인크래프트 기본 코드를 고칠 필요가 없게 되었습니다.

 

과정에서 '모드' 라는 프로그램의 개념이 완전히 달라지게 되는데, 이전에는 마인크래프트 코드를 수정하는 형식이었으나

 

이제는 간단히 BaseMod 상속하는 객체 하나가 여러가지에 접근할 있는 형태로 바뀐 것입니다.

 

 

3. 마인크래프트 포지 (Minecraft Forge)

 

 

마인크래프트 포지는 리수가미의 모드로더와 유사한 모드 제작 플랫폼으로서,

 

Minecraft beta 1.7.3 버전에서 처음 등장하였습니다.

 

어쩌면 리수가미의 모드로더에서 영감을 받아 제작되었을 가능성도 있지만 자세한 내막은 알려져 있지 않습니다.

 

마인크래프트 포지는 Minecraft Forge Forge ModLoader 2가지 모드로 구성되는데,

 

Forge ModLoader 리수가미의 모드로더처럼 모드를 로딩해 주는 역할을 하며,

 

Minecraft Forge 모드 제작 API로서, 모드 제작을 용이하게 줍니다.

 

사실 Forge ModLoader(FML)만으로 모드 제작은 가능합니다. 간단히 포지 모드를 로딩해 주는 모드로더만 있더라도 실행되기 때문입니다.

 

하지만, 이것만으로는 모드 제작 자체가 불가능할 정도로 Minecraft Forge라는 API 모드 제작에서 중요한 역할을 맡고 있습니다.

 

예를 들어보자면, 가장 최근 정식 1.8 버전에서 일어났던 일이 있습니다.

 

사실 1.8 버전에서는 우선 FML 먼저 출시되었었지요. 이것만으로도 일부 모드들은 1.8 업데이트되었었습니다.

 

하지만 포지 API 없는 이런 업데이트는 너무도 어려운 일이었고, 사실상 대부분의 모드들은 1.8 포지 API 나올 때까지

 

기다릴 수밖에 없었지요.

 

포지 API 대해 설명을 하자면,

 

원래 포지 API 레지스트리, 인터페이스 다양한 방식의 API 골고루 지원해 왔습니다.

 

중에서도 레지스트리가 미미하게나마 비중이 높았죠.

 

하지만 최근 들어서는 이벤트 쪽으로 움직이는 강한 경향이 나타나고 있으며,

 

따라서 모드 제작에서도 이벤트 처리가 점차 중요해지고 있는 추세입니다.

 

이외에, 세부 사항에 대해서는 다음 강좌들을 통해 차차 설명할 계획입니다.

 

4. 결과

 

모드로더와 포지가 나온 이후, 여러 모드들이 서로 호환되기 위하여 이들을 기반으로 하는 모드들을 만들기 시작했고,

 

얼마 MCP 자체만으로 모드를 만드는 사람들은 별로 남지 않게 되었습니다.

 

 

원래 베타 후기에서 정품 초기까지의 버전들에서는 모드로더와 포지가 병존했기 때문에,

 

중에서 무엇을 선택할지에 대한 선택권이 있었습니다.

 

이때까지는 모드로더 전용 모드 제작자 계열과 포지 전용 모드 제작자 계열이 나뉘어 있었는데, 모드로더가 먼저 생겼으므로

많은 모드가 모드로더를 이용하여 작성되는 편이었습니다.

 

하지만 모드로더에는 중대한 문제가 하나 있습니다.

 

바로 '단일 제작자' 리수가미가 혼자서 창조하고 관리해 왔다는 것이지요. (아마 독단적으로 운영했던 같습니다.)

 

그러다 보니, 리수가미가 '그만두기만 하면' 모드로더는 모든 것이 끝인 되어 버린 겁니다.

 

게다가, 리수가미는 모드로더 뿐만 아니라 여러 모드를 함께 제작하고 있기 때문에, 모드로더 자체에 전념할 수가 없었습니다.

 

반면 다수의 서포터들이 존재했던 포지는 상황이 전혀 달랐지요.

 

처음부터 LexManos, cpw, Eloraam 등의 여러 제작자가 함께 제작하였으며,

 

현재 cpw 등이 그만두면서 결국 LexManos라는 단일 제작자가 이어나가게 되었지만,

 

여전히 주위에 많은 개발자들이 많은 측면에서 돕고 있었습니다.

 

게다가 LexManos 포지로 먹고 사는 처지가 되었으니 그쪽에 전념할 수밖에 없었죠.

(실제로 그가 제작하거나 기여한 모드는 Minecraft Forge Forge Mod Loader 뿐입니다...)

 

결과적으로 모드로더는 업데이트도 늦고, API 개선도 별로 없었기에,

 

시간이 가면서 나날이 발전해 갔던 포지에 비해 점점 뒤쳐지게 되었고,

 

제작자인 리수가미가 이상 모드로더를 이어 나가기 힘들게 되면서, 사실상 작별을 고하게 됩니다.

 

특히 1.6, 1.7, 1.8에서 이어지는 강력한 모장의 마크 기반 코드 변경을 단일 코더인 리수가미가 버텨내기는 어려웠을 것이며,

그래서 1.6.2 버전까지만 업데이트 것으로 보입니다.

 

결과적으로 이러한 이유들로 인하여, 포지 중심으로 모드 제작이 옮겨가게 되었습니다.

 

(현재는 MCP 팀도 Minecraft Forge 권장하더군요. 그러니 이제 마크 공인 모드 제작 플랫폼이 겁니다.)

 

 

* 5. 버킷과 포지의 차이

 

 vs.  

 

댓글 중에서 버킷과 포지를 질문한 분이 있었습니다. 차이에 대해 궁금하실 분들이 많다고 보기에,

 

이렇게 따로 설명해 드리고자 합니다.

 

우선, 근본적인 차이는 다음과 같습니다.

 

1. Minecraft Forge 마인크래프트 클라이언트와 서버를 모두 수정할 있습니다.

    반면 Bukkit API 서버에 대한 변경만을 지원합니다.

 

2. Minecraft Forge 모드로 하여금 서로 호환되면서도 마인크래프트 기본 코드를 많이 건드릴 있게 해줍니다.

   반면 Bukkit API Abstraction API 방식을 사용함으로서, 플러그인에게 간접적으로 접근할 있는 권한만 부여합니다.

 

 

아마 1번의 차이점은 많이 들어보셨을 텐데요, 세부 사항에 대해서는 아마 모르는 분이 계실지도 모릅니다.

 

차이점은, 기본적으로 버킷은 마인크래프트 서버 프로그램을 변경한 프로그램이라는 사실로부터 나옵니다.

 

버킷으로서는 마인크래프트 코드를 그대로 이용할 이유가 없으며,

 

단지 클라이언트와 제대로 통신만 있으면 전혀 문제가 없습니다.

 

사실, 버킷은 원래 C Python같은 다른 언어로 만들어질 수도 있었습니다. (그리고 실제로 그런 것이 있습니다..)

 

그러하니 버킷으로서는 서버 파일을 자의적으로, 마음대로 변경할 있었고,

 

결과적으로 코딩하기 쉬운 방법으로 바꾸었던 것으로 보입니다. 실제 많은 변경이 가해지지는 않은 것으로 보입니다만..

 

플러그인 제작자 분들께서 사용하시는 버킷 API '버킷'이라는 프로그램에 접근할 있도록 주는 API이며,

 

실제로 버킷에서 일부 이벤트만 받아 처리할 있도록 해주는 아주 일부의 변경만을 지원할 뿐임에도 불구하고

 

그러한 이점으로 인해 상당히 많은 부분에 접근하여 많은 변경을 가할 있는 구조를 가지고 있습니다.

 

 

반면, 포지는 MCP 딸린 모드입니다. 물론 마인크래프트 코드를 변경하지만, 아무래도 조심스러울 수밖에 없었습니다.

 

잘못하면 이로 인해 마인크래프트의 본질을 심각하게 훼손할 수도 있기 때문이죠.

 

그래서 처음부터 포지가 세운 원칙 중에 '마인크래프트 코드는 있으면 적게 고친다' 라는 것이 있습니다.

 

또한 최근에 MCP 코드 패치 파일을 만드는 제도로 바뀌면서,

 

원칙은 Minecraft Forge 개발버전 크기를 최소한으로 줄이기 위한 하나의 방법이 되기도 하였습니다.

 

이러한 제한으로 인해, 서버 부문에서는 버킷의 기능이 모두 구현 가능하지만, 그다지 이점이 없는 상태이기도 합니다.

 

  (그래도 기본 코드를 효율적으로 이용하고 변경할 있기 때문에,

         서버 모드는 실제적으로 버킷보다 많은 것을 있습니다)

 

 

2번의 차이점은 아마 들어보지 못하셨던 분들이 많을 것으로 생각됩니다. 부연 설명을 하자면,

 

예를 들어 마인크래프트의 블럭에 접근할 있도록 해주는 Block이라는 객체가 도구에 어떻게 구현되어 있는지를 살펴보면 좋을 것입니다.

 

 

 

마인크래프트 포지에서는, 그냥 마인크래프트 원래 코드에 있는 Block 사용하되,

 

일부를 고쳐 접근하게 쉽게 만드는 방법을 사용합니다.

 

블럭을 새로 만들고자 때에도 Block 상속받는 클래스를 하나 만들고,

 

접근하고자 때도 마찬가지로 Block 클래스를 통해 접근합니다. 마인크래프트 기본 코드를 적극 활용하는 것입니다.

 

또한 이를 통해 마인크래프트 기본 코드가 어떤 식으로 작동되는지도 수도 있고,

 

모드 제작시에도 이를 따라 하는 것이 하나의 좋은 모딩 방법으로 공인되어 있습니다.

 

 

 

반면, 버킷에서는 Block 인터페이스입니다. 외부에서 접근할 있는 일부 함수만이 주어져 있죠.

 

아마 버킷 내부에서 실제 Block 나타내는 객체와 연결이 되어있을 것으로 보이는데, 자세한 내막은 없어요.

 

마인크래프트의 기본 코드는 고사하고 버킷 내부에서 어떻게 작동하는지도 없다는 것입니다.

 

플러그인으로서는 'Bukkit API'라는 버킷의 외부 경계면만 있고 접근할 있는 것이죠.

 

 

이러한 차이는, 궁극적으로 1번의 차이점에서 유래한 것으로 보입니다.

 

위에서 서술하였듯이, 버킷과 달리 포지는 마인크래프트 코드를 수정하는 데에 제한이 있기 때문에,

 

그에 상당하는 API 구축하는 데에는 상당한 어려움이 있습니다.

 

대신 포지는 모드로 하여금 마인크래프트 코드 자체에 직접 접근할 있도록 함으로서,

 

상당히 많은 부분을 고치고 제어할 있는 권한을 모드 제작자에게 부여합니다.

 

그럼으로서, 모드의 가능성은 (서버에서만 돌아가는 '서버 모드' 대해서도) 플러그인을 능가하는 수준이 됩니다.

 

또한 마인크래프트 기본 코드를 봄으로서 코드를 어떻게 작성해야 자신이 원하는 효과를 얻을 있는지에 관해

많은 통찰력을 얻을 수도 있다는 사실도 얼마간 이에 작용한 것으로 보입니다.

 

이렇게 만들 경우 가지 단점이 있는데,

 

하나는 마인크래프트가 업데이트될 때마다 모드도 업데이트해 주어야 한다는 것입니다.

 

대개 마인크래프트 버전이 업데이트될 때마다 코드가 바뀌게 되는데,

 

아주 사소한 차이라고 할지라도 모드가 바뀐 부분을 사용하거나 언급이라도 한다면, 버전과 호환되지 않게 됩니다.

 

또한 마인크래프트의 '난독화' 버전마다 달라지기 때문에, 모드로서 여러 버전에 호환되는 것은 애초에 불가능한 일이 됩니다.

 

버킷의 경우 마인크래프트 자체 코드에 접근하지 않기 때문에 그러한 일이 생기지 않죠.

 

그렇기 때문에, 포지도 버킷처럼 Abstraction API 방식으로 바꾸어야 한다는 말도 많았지만

 

포지 제작자 LexManos 이러한 요구들을 모두 거부했습니다.

 

그러자, 일부 사람들은 Forge 위에 Abstraction API 올리는 일을 시도하기 시작했습니다. 물론 힘든 일입니다.

 

특히 포지 초기 버전에서는 Forge API 수준이 미흡했기 때문에 그러한 일이 거의 불가능하다시피 했습니다.

 

하지만 시간이 가면서 Forge API 발전을 거듭하였고,

 

근래에는 Abstraction API 포지 기반에 제작하는 것이 가능해지는 수준에 이르게 되었습니다.

 

때맞추어 버킷이 DCMA 소동에 휩싸이면서 모드 버킷(mcpc, Cauldron) 제작자들과 버킷 쪽에 종사하던 일부 주도적인 플러그인 제작자들이 포지를 기반으로 하는 '버킷 대용품' 제작에 나섰고,

 

 

결과 Sponge 탄생하게 되었습니다.

 

Sponge 제작자들은 Forge 위에 Abstraction API 올리는 것을 시도하고 있고, 현재까지는 성공적인 것으로 보입니다.

 

 

어쨌거나.. 지금까지 Minecraft Forge의 역사에 대해 알아보고, Bukkit 차이점을 알아보았습니다.

Posted by Abastro