강좌/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