목표: 구리 블럭으로 포탈 게이트를 만들고, 바다의 심장 아이템으로 게이트를 활성화 시키기

 

참고 기능: 흑요석으로 불을 붙이고 네더 포탈을 활성화 시키는 기능

 

추측한 원리 및 과정

- Fire 블록이 흑요석 위에 설치되었을 때, 아래가 흑요석이라면 포탈 게이트의 구성을 확인하고 사이에 있는 Air 블록들을 포탈 블럭으로 바꾸는 방식

 

선정한 Block Hooking 과정

1. Fire 블록을 설치할 수 있는 아이템(라이터, 화염구) 등에서 설치되는 블럭이 Fire 블록이 아닌 대체하는 블록(이하, 가짜 불 블록)을 설치하도록 기능

2. 가짜 불 블록이 설치되었을 때, 원하는 프레임이 구성되어있는지 확인

3-1. 구성되지 않았다면 가짜 불 블록이 있던 위치에 Fire 블록으로 대체

3-2. 구성되었다면 2번 과정에서 산출한 사이 Air블록들을 커스텀 포탈 블록으로 대체

 

선정한 Item Hooking 과정

- 주요 포인트

1) 바다의 심장이라는 아이템을 사용하였을 때, AfterEvents 중에서 ItemUseOn 이벤트가 아닌 ItemUse 이벤트만 호출 시키기 때문에 사용하고자한 위치를 특정하기 어려움.
2) BeforeEvents 중에서는 ItemUseOn 이벤트를 호출하긴 하는데, 클릭을 누르고 있는 동안 다회차로 호출되는 문제가 있음

3) 때문에 BeforeEvents를 호출하는 과정에서 이를 소스코드로 제어하기 보다는 가짜 아이템을 바다의 심장으로 위장시켜 바다의 심장 역할을 대체하는 것이 간단하다고 판단.

4) 바다의 심장 아이템 생성 및 사용처: buried_treasure loot_table에서만 습득 가능, conduit 제작에서 재료로 활용

 

- 과정

1. 바다의 심장의 모습을 가진 가짜 아이템(이하, 가짜 심장)이 사용하였을 때, 가짜 불 블록을 설치하는 block_placer Component를 가지도록 설계

2. chests/buriedtreasure.json에서 바다의 심장 대신, 가짜 심장 아이템이 들어있도록 작성

3. recipes에 conduit을 제작할 때, 가짜 심장 아이템을 사용하도록 작성

4. AfterEvents 중 ItemUseOn이 발생시키는 라이터와 화염구 같은 아이템은 블록을 바꾸는 방식으로 해결 가능

 

- 스크립트 설계를 포기한 이유

1. 사용하고자 하는 아이템의 습득 경로 및 사용 경로가 매우 적음 => 염색약, 물약 재료등 사용처도 많고 습득 경로도 많은 아이템의 경우는 경우의 수를 다 차단하기엔 어려움

2. 인덱스로 구성된 것 같은 마인크래프트 블록은 중복처리를 좌표 형태로 구성 가능성이 있으나 몇 가지 우려지점이 발생.

  - 추측 사항: Behaviour 팩은 서버를 가동 시키는 클라이언트에서만 실행(Dedicated건 Listen이건).

  - 우려 사항

    - 게이트 형태로 다루기에는 서버단에서 발생하는 이야기라 난해.

    - 리퀘스트 형태로 다루려면, 전달해야하는 정보가 많아지는데, 이걸 중복 처리를 해야하는 것이 귀찮음. => 이게 주된 이유, 로직 고민하다가 백날천날로 밀려남.

    - 굳이굳이 처리할 수 있다고 만들어둔 itemUseOn AfterEvent 핸들러를 못쓰는게 열받음. => BeforeEvent 핸들러는 있는데 왜 AfterEvent 핸들러로는 작동하지 않는지(아이템의 성향에 따라 작동하는게 다르다는 것은 이해함)가 마음에 들지 않음. 이벤트 콜을 하기 위해서 callback들을 걸어놔도 여전히 이 콜백들을 중복 처리를 해야하기 때문에 원리 파악하고 재구성하는데 시간이 걸리기 때문에 하기 싫습니다. 돈 받고 만드는 것도 아닌데요...

 

 

근본적인 원인

- Addon을 작성할 때 사용하는 Behaviour Pack에서는 기존 블럭의 json들을 override하는 것을 허용하지 않습니다. 파일명으로 하기 보다는 내부의 identifier를 활용하여 블럭의 작동방식에 대해 기술할 수 있는데, 이때 "minecraft:"를 활용하는 것을 허용하지 않는 것으로 알고 있습니다.

 

그래도 가급적 스크립트나 고유 json에서 다뤄졌으면 좋겠는 이유

 현재 방식은 기존 아이템을 게임 내에서 단절 및 배제하고 대용 커스텀 아이템이 그 자리를 대체하는 방식이기 때문에 사용 폭이 제한이 되어있습니다. 또한 새로운 업데이트를 통해 새로운 루트가 생긴다면, 정상적으로 작동하지 않을 가능성이 높습니다. 언제든 작동하지 않을 가능성이 높은 컨텐츠는 유지 보수에 시간과 에너지를 지속적으로 투자하게 되기 때문에 관리를 해줄 수 없는 크리에이터들에게는 부담을, 즐겁게 사용하는 사용자들에게는 불완전함을 전달하는 계기가 될 것이라고 생각합니다.

'개발자로 > MinecraftMod' 카테고리의 다른 글

ProccupationWar #007, BDS 패킷 테스트  (0) 2024.11.20
ProccupationWar #006, 특수 블록 게이트 생성(Minecraft BE Addon)  (0) 2024.11.14
ProccupationWar #004  (0) 2024.11.05
ProccupationWar #003  (0) 2024.09.23
ItemLocker #001  (0) 2024.07.07

문제점

Minecraft Bedrock의 경우(파악한 내용으로), 일반 Vanila 블록들의 루팅 값을 수정하긴 어려울 것 같다.

 

사용처

- 곡괭이로 광질하는 광석 블록의 루팅에 대해 추가적인 보상을 하기 위함

 

파악한 내용

- Vanila 블럭을 위한 loot 값 변경을 위한 디렉토리 구조가 존재하지 않음

- 바닐라 블럭의 loot 관련 컴포넌트를 typescript로 직접 접근하여, World Init 이벤트에서 이를 수정하고자 했으나, 방법을 찾지 못함

 

가능한 선에서 구상한 내용

- Player가 블럭을 부쉈을 때 발생하는 playerBreakBlock 이벤트의 Before 시점과 After 시점을 활용하여 /loot 커멘드를 실행시켜 유사한 내용을 만드는 것

 

한계

- 기존 Vanila 루팅 값을 지우지는 못함

- playerBreakBlock의 Before 이벤트에서 플레이어의 아이템 스택, 부수는 블럭 뿐만 아니라 cancel에 대해서도 접근할 수 있었는데, 이 때 cancel 값을 true로 하면 부서지지 않는다.

- 블록을 부수어서 playerBreakBlock의 After 이벤트까지 가는 것보다, Before 이벤트에서 cancel을 true값으로 만들어 부수지 않고, 블럭을 air로 대체하고 원하는 loot 파일을 호출하는 것으로 이를 해결하고자 하였지만, Block을 바꾸는 것에 있어서 권한을 묻지 않으면(추측) 이를 거부한다.


당면한 문제 01

- runcommand 함수 역시 op관련 권한을 "privilege"를 묻는다. => /loot command를 사용할 수 없음

> 근원적인 문제, 왜 모든 플레이어에게 Op를 제공하면 안되는가?

  > 신뢰할 수 있는 플레이어들에게만 Op권한을 제공하여야 관리나 보안적인 측면에서 적합하기 때문

∴ 다른 우회 경로 탐색 필요

 

- ItemStack을 만들어서 뿌리는 것 역시 Privilege 요구

 

1) 단순 해결: 이벤트 처리와 동시에 op권한 제공, 이벤트 종료와 동시에 op 권한 박탈 방식

 > 문제: 다인원이 게임 상 수십개나 Break 이벤트를 발생 시키는 중에 이 과정에서 op 권한이 주어졌다가 박탈되는 과정에서 프로그램이 에러가 나서 강제 종료, 급작스럽게 종료되는 과정에서 문제가 발생할 가능성이 높아짐.

 

2) 눈속임 해결: 모든 블록의 루팅 내용을 수정할 수는 없지만, 일부라도 루팅율(하나 캤을 때, 획득하는 아이템량)을 개선 시킬 수 있음.

  > 단계: 목표 블럭 종류(돌, 철광석, 금광석, 다이아 광석)를 Custom 블럭으로 복제 > 해당 블럭 json 파일의 loot 컴포넌트 내용을 원하는 루팅 파일 경로로 설정 > feature 디렉토리에서 Custom 블록의 스폰을 담당하는 파일을 만들어 대칭되는 Vanila 블럭의 일부를 대체함

  > 문제: custom 블럭을 광물 취급하는 방식으로 진행되는데, feature에서 덩어리지는 광물 개수를 설정하는 것이 있다. 돌의 경우는 덩어리지는 광물로 설정할 수 없기 때문에 포기

 

3) Privilege 문제 해결

> Privilege는 op와는 다른 문제이고, 이는 다음과 같은 코드로 해결할 수 있었다.

system.run(() => {
// 특정함수
});

> 애초에 원하는 대로 시스템을 구성할 수 있게 됌. 가짜로 부수는 것으로 보이는 것도 가능하게 됌.

> 추가 예상 문제 - 많은 사람이 블럭을 캤을 때, 어떻게 작동할지 모름.


Privilege 요구 Script 함수(경험 상)

- runCommand

- dimension.spawnItem

 

Privilege 이해 상황

- 인게임 내에서 Op 권한으로 추측 중

- server Behaviour 팩에서 인위적으로 만드는 함수인데, 이걸 privilege를 요구하는게 맞나 싶다가도... 서버에 올려서 필수 팩으로 돌리는 걸로는 우회가 안되려나 => 어짜피 연습용 팩으로 공유할 수 있게 할 건데 일반 맵으로 열지 못하면 의미가 없음

 

Privilege 1차 이해 상황 업데이트

- Op 아님

- 주로 Before Event들에만 주로 사용되는 시스템인데, 문제가 발생할 수 있는 Native 함수를 Before Event Handler 함수들과 동일한 Tick에서 실행되지 않기를 원해서 도입한거라고 한다.(제대로 이해한게 맞다면)

* 참고 사이트: Script Core Features | Bedrock Wiki

 

Script Core Features | Bedrock Wiki

 

wiki.bedrock.dev

 

변경 사항

version Java를 위한 Forge Mod  =>  version Bedrock을 위한 Microsoft Minecraft Addon

변경 사유

- Java 버전 마크를 잘 안함

- 서버 내에 공유되는 변수를 만들기 위해 필요한 내용이 많아 시간이 필요할 듯(네트워크 패킷 등)

 

Bedrock(실질적 Win10이나 이하 Bedrock으로 통칭) 장점

- 공식 문서 있음

- 자주 접속하기 쉬움

- 기존 Bedrock 클라이언트로도 테스트 가능

 

Bedrock 단점

- Java 언어는 해본 적이라도 있지 JavaScript는 처음 해봄. 특히 TypeScript를 끼고하는 건 더더욱

- 지원되는 범위 폭이 좁음 > defendencies은 죄다 beta, 맵 제작을 위해 클라이언트 Preview 버전을 끼고 제작하고 있음

- 공식 문서에 나오지 않은 영역도 존재함

- 신규 UI를 등록하고 활용하는 방안이 어려움

- 전반적으로 json파일을 활용하여 객체들을 표현하는데 너무 다양함.

 

API Beta 사용 이유

> op 권한을 가진 플레이어들이 /scriptevent로 스크립트 내부 함수를 사용하는 방식이 있으나, op권한을 가지지 않은 플레이어들이 명령어를 쓰기 위해 채팅 입력시 발생하는 이벤트 ChatSendBefore를 사용할 필요가 있었음

 

Preview 사용 이유

> 공허 맵을 제작하는 데 있어 Java에서 만들어 베드락 전환, 커맨드로 지우기 등 방법이 있었지만, Editor 기능을 위해 깔았던 Preview에서 제공을 한다길래 사용

 

고민 사항

- 다중 맵으로 구성된 컨텐츠라 게임 내에서 이를 조정하고 싶은데 지원되는 영역인지, 그냥 로컬로 돌려야하는지 고민.

ex> 서버를 1,2,3,4를 한 컴퓨터에 넣어두고 127.0.0.1:<다른 포트번호>로 돌리면 되지 않을까 고민 중. 이왕이면 1~2 맵은 게임 시스템 상으로 묶을 수 있다면 좋을 듯. 사실 상 공간을 크게 활용하지 않는 맵들도 다수 존재하기 때문(하지만 내부 구성은 오버월드여야해서 영역이 겹침).

- GUI를 어디서 부터 어디까지 손을 대야하는지 고민. 컨텐츠를 팀 경매까지 확장하면 그 부분까지 하고 싶긴 하나, 새로운 키를 할당하고 이에 맞는 UI를 작성하거나 UI에 데이터 값을 전달하는데 아직 파악하지 못함.

 

 

 

'개발자로 > MinecraftMod' 카테고리의 다른 글

ProccupationWar #005, Minecraft Bedrock Hooking 경험(기존 기능 바꿔치기)  (0) 2024.11.13
ProccupationWar #004  (0) 2024.11.05
ItemLocker #001  (0) 2024.07.07
ProccupationWar #002  (0) 2024.02.20
ProccupationWar #001  (0) 2024.02.20

고민

 블럭하나에 저장할 내용이 많아서 추가하고 있는데 블럭 엔티티가 많으면 렉을 유발할 수 있다는 내용을 forge 문서에서 본적이 있다. 일반 블럭들보다 블럭 엔티티가 다루는 정보가 더 많아서 그런게 아닐까 추측해본다. 만약 그렇다면, 지금 내가 만드려는 것은 상자 블럭엔티티가 저장하는 데이터(아이템 스택 27개)보다 더 많은 데이터를 저장하는 것은 지양해야할까? 

 

# 목표 기능

: 아이템을 일종의 비밀번호화하여 잠금 설정 혹은 해금 시도할 수 있는 메뉴

 

# 구현 방식

- 리소스: 포토샵 제작(Hopper 재활용)

- Menu, 커스텀 슬롯: 최대 스택이 1, 올릴 수 없는 기타 아이템(인챈트 된 아이템 등)을 구별.

 

# 해결한 문제

- BlockEntityRender 문제

> 문제 상황: Block이 BlockEntity를 가지면서 Render가 안되었던 상태.

  > 조건: 기존 BlockEntity의 외형을 가져올 것, 추가적인 커스텀 Renderer는 구현하지 않음

  > 해결

@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
  public static class ClientModEvents{
      
    // @SubscribeEvent
    // public static void onClientSetup(FMLClientSetupEvent event){
    //   event.enqueueWork(() -> MenuScreens.register(ITEMLOCK_SET_MENU.get(), ItemLockSetScreen::new));
    //   LOGGER.debug("ITEMLOCKER, ClientSetUp Complete");
    // }

    @SubscribeEvent 
    public static void RegisterRenderers(RegisterRenderers event){
      event.registerBlockEntityRenderer(ItemLocker.ITMELOCK_CHEST_BLOCKENTITY.get(), ChestRenderer::new);
      LOGGER.debug("ITEMLOCKER, RegisterRenderers Complete");
    }
    // 이 이벤트를 통해 기존의 BlockEntity의 외형을 그대로 가져올 수 있었음.
  }

- Menu의 Container 문제

 > 문제 상황: ProccupationWar#002의 영상에서 메뉴를 열 때마다 슬롯의 내용이 없어짐.

   > 조건: 창을 닫았을 때와 같은 Container의 내용을 가져올 것

   > 해결

      1. BlockEntity에서 Container를 saveAddtional & loadAdditional을 통해 CompoundTag에 저장 및 로드

// BlockEntity를 상속 받은 클래스에서

@Override
  protected void loadAdditional(CompoundTag p_331054_, Provider p_334909_) {
    super.loadAdditional(p_331054_, p_334909_);
    
    this.passwords = NonNullList.withSize(5, ItemStack.EMPTY);
    PasswordHelper.loadAllPasswords(p_331054_, passwords, p_334909_);
    
  }
  
  @Override
  protected void saveAdditional(CompoundTag p_187489_, Provider p_328166_) {
    super.saveAdditional(p_187489_, p_328166_);
    PasswordHelper.saveAllPasswords(p_187489_,passwords,p_328166_);
  }

 

      2. Menu를 생성할 때, Container 전달

ItemLockSetMenu(p_59082_, p_59083_,this);
// 여기서 this는 BlockEntity를 상속한 클래스

        * 주의, Menu에서는 매 순간 새로 생성하는 것과 다를바가 없으니, 저장할 내용이 있다면  BlockEntity 클래스를 상속받은 클래스에 CompoundTag로 저장.

 

 

# 추가 구현 연계

- Entity or Menu, 주인에 따른 다른 기능 구현

- Menu, 잠금 상태를 확인할 수 있는 DataSlot 추가

- Screen, DataSlot 표기, 다양한 기능을 하는 확인 버튼 추가

- 큰 상자로 변모했을 때, BlockEntity 동기화

 

 

'개발자로 > MinecraftMod' 카테고리의 다른 글

ProccupationWar #004  (0) 2024.11.05
ProccupationWar #003  (0) 2024.09.23
ProccupationWar #002  (0) 2024.02.20
ProccupationWar #001  (0) 2024.02.20
Minecraft Forge Add Custom Block  (0) 2023.07.04

+ Recent posts