효율적인 모드 서버 운영을 위해
친구들과 함께 게임을 하면서 종종 마인크래프트 모드 서버를 운영하고는 한다. 이럴 때 가장 큰 문제는 다수의 모드를 사용하면서 생기는 서버 성능 문제다. 대부분의 모드 호환성이나 맵 로딩 문제는 설정을 제한하거나 맵을 사전 로딩 시켜놓는 방식으로 해결할 수 있다. 아니면 물리적으로 서버 사양을 빵빵하게 주면 해결된다.
가장 큰 문제는 겉날개에 있다.
겉날개와 폭죽을 사용한 부스트로 인해 맵 로딩보다 더 빠른 이동으로 서버에 굉장히 많은 부하를 주고 있다.
이를 해결하기 위해 근본이 되는 겉날개 자체를 사용하지 못하도록 하는 방안을 찾아보던 중 KubeJS라는 모드를 알게 되어서 이를 활용하고자 한다.
KubeJS란 무엇인가?
모드 다운로드 페이지 : KubeJS - Modrinth
KubeJS는 JavaScript를 사용해서 마인크래프트를 커스터마이징할 수 있게 해주는 모드다.
보통 마인크래프트 모드를 만들려면 Java 코드를 작성하고 컴파일하고 패키징하는 복잡한 과정을 거쳐야 하는데, KubeJS를 사용하면 JavaScript 스크립트만으로 다양한 기능을 구현할 수 있다.
주요 기능
KubeJS로 할 수 있는 것들은 굉장히 많다
- 레시피 편집: 제작법을 추가, 수정, 삭제할 수 있다
- 아이템/블록 추가: 새로운 아이템이나 블록을 등록할 수 있다
- 월드 이벤트 스크립팅: 플레이어 로그인, 블록 파괴, 몬스터 스폰 등 다양한 게임 이벤트에 반응할 수 있다
- 아이템 사용 제한: 특정 아이템의 사용을 막거나 제한할 수 있다 (지금 필요한 기능이다)
- 다른 모드와의 통합: FTB Quests 같은 다른 모드들과 연동할 수 있다
스크립트 실행 시점
KubeJS는 세 가지 시점에 스크립트를 실행한다:
- Startup: 게임이 시작될 때 한 번 실행 (아이템/블록 등록용)
- Server: 월드에 접속할 때 실행 (레시피, 이벤트 처리용)
- Client: 클라이언트 측에서 실행 (UI 커스터마이징용)
우리가 겉날개 사용을 막으려면 Server 스크립트에서 아이템 사용 이벤트를 가로채면 된다.
적용방법
우선 KubeJS와 의존성 모드인 Rhino를 설치했다는 가정하에 진행한다.
스크립트는 마인크래프트 서버 내 kubejs/server_scripts 경로에 JavaScript 파일로 작성하면 된다.
겉날개 사용을 차단하려는 것이지만, 엔드에서 힘들게 얻은 겉날개를 강제로 빼앗으면 서버 내 플레이어들의 분노를 살 수 있으니 적당한 보상으로 교환하게 할 예정이다.
겉날개의 가치를 생각해보면 네더라이트 주괴 1개 정도가 적당하다고 생각하여 다음과 같은 동작을 제공할 것이다.
동작 흐름도
1. 플레이어의 인벤토리를 주기적으로 체크 (5초마다)
↓
2. 겉날개 아이템이 감지되는가?
├─ 예 → 3단계로 진행
└─ 아니오 → 1단계로 돌아감
↓
3. 감지된 겉날개 아이템 제거
↓
4. 네더라이트 주괴 1개를 플레이어에게 지급
↓
5. 플레이어에게 경고 메시지 출력
("겉날개는 서버 성능을 위해 네더라이트 주괴로 교환되었습니다!")
↓
6. 1단계로 돌아가서 계속 감시
이런 방식으로 동작하면 플레이어가 겉날개를 획득하는 즉시 자동으로 네더라이트 주괴로 교환되어 서버 성능 저하를 방지할 수 있다.
이제 이 동작 흐름에 맞게 스크립트를 작성해보자.
스크립트 작성
스크립트 작성은 Claude Code의 도움을 받았다.
// kubejs/server_scripts/elytra_block.js
var ELYTRA_ID = "minecraft:elytra";
var REPLACE_ITEM = "minecraft:netherite_ingot";
var CHECK_INTERVAL = 20;
PlayerEvents.tick(function(event) {
var player = event.player;
if (player.tickCount % CHECK_INTERVAL !== 0) return;
// 1. 장비 슬롯 검사 (흉갑 슬롯 위주)
var armorSlotNames = ["chest", "head", "legs", "feet"];
for (var s = 0; s < armorSlotNames.length; s++) {
var slotName = armorSlotNames[s];
var armorItem = player.getItemBySlot(slotName);
if (armorItem && armorItem.id === ELYTRA_ID) {
player.setItemInSlot(slotName, Item.of(REPLACE_ITEM));
player.tell("§c[서버] 겉날개는 이 서버에서 사용이 금지되어 있습니다.");
console.info("[ElytraBan] " + player.username + " 장비 슬롯(" + slotName + ")에서 겉날개 제거");
}
}
// 2. 인벤토리 전체 검사
var inv = player.inventory;
var invSize = inv.containerSize;
for (var i = 0; i < invSize; i++) {
var invItem = inv.getItem(i);
if (invItem && invItem.id === ELYTRA_ID) {
inv.setItem(i, Item.of(REPLACE_ITEM));
player.tell("§c[서버] 겉날개는 이 서버에서 사용이 금지되어 있습니다.");
console.info("[ElytraBan] " + player.username + " 인벤토리 슬롯 " + i + "에서 겉날개 제거");
}
}
});
이제 적용을 위해 서버 내에서 /reload 명령어로 새로고침하거나 서버를 재시작하면 된다.
마무리
위 과정을 통해 서버 내 겉날개 사용을 효과적으로 제한했다.
대신 플레이어들의 불만을 잠재우기 위해 이동속도는 느리지만 공중 체공이 가능한 제트팩 모드를 추가함으로써 이동에 대한 영향은 줄였다.
추후 KubeJS를 통해 여러 가지 유용한 스크립트를 만들 수 있게 되어 활용할 곳이 많아졌다.