Table of Contents
사이드
마인크래프트는 클라이언트-서버 모델을 사용합니다. 즉, 사용자는 게임 클라이언트를 설치하고 서버에 연결하여 게임을 플레이합니다. Fabric은 모드가 마인크래프트 클라이언트나 서버, 또는 동시에 둘 다를 타겟팅할 수 있게 해줍니다.
마인크래프트에서 클라이언트/서버의 개념은 물리적 또는 논리적 사이드를 의미할 수 있어 모호합니다. 클라이언트/서버라는 용어는 서로 다른 마인크래프트 배포판(마인크래프트 클라이언트와 전용 서버)을 구분하는 데 사용될 수 있는데, 이를 “물리적” 사이드라고 합니다. 하지만, 마인크래프트 클라이언트는 싱글플레이어 및 LAN 세션을 위한 자체 통합 서버를 호스팅하기 때문에 클라이언트에도 서버 로직이 포함되어 있습니다. 따라서 클라이언트/서버는 게임 로직의 일부를 구분하는 “논리적” 사이드를 나타낼 수도 있습니다.
두 유형의 사이드 모두 '클라이언트'와 '서버'가 존재합니다. 하지만 논리적 클라이언트는 물리적 클라이언트와 동일하지 않으며, 논리적 서버도 물리적 서버와 동일하지 않습니다. 논리적 클라이언트는 물리적 클라이언트에 의해 호스팅되고, 논리적 서버는 물리적 서버 또는 물리적 클라이언트에 의해 호스팅됩니다.
논리적 사이드는 두 마인크래프트 배포판의 아키텍처에서 중심적인 역할을 합니다. 따라서 논리적 사이드를 이해하는 것은 Fabric으로 모드를 개발할 때 매우 중요합니다.
물리적 사이드
물리적 사이드 또는 환경은 두 가지 마인크래프트 배포판(클라이언트와 서버)을 의미합니다. 클라이언트는 바닐라 런처에서 실행되는 프로그램이며, 서버는 마인크래프트 공식 사이트에서 무료로 다운로드할 수 있습니다. 물리적 사이드는 현재 환경에서 어떤 코드가 사용 가능한지를 나타냅니다.
클라이언트와 서버 환경은 동일한 프로그램의 축소된 배포판으로, 필요한 부분의 코드만 포함하고 있습니다.
Fabric에서는 @Environment(EnvType.CLIENT)
와 같은 주석을 자주 볼 수 있습니다. 이는 특정 코드가 한 환경에서만 존재함을 나타내며, 이 예시에서는 클라이언트를 의미합니다.
Fabric의 fabric.mod.json과 mixin 구성에서 클라이언트/서버는 환경을 의미합니다.
각 물리적 사이드는 진입점으로 사용되는 클래스와 데이터 생성기 클래스가 함께 제공됩니다. 진입점은 net.minecraft.data.Main
입니다.
논리적 사이드
논리적 사이드는 실제 게임 로직을 담당합니다. 논리적 클라이언트는 렌더링, 플레이어 입력 전송, 리소스 팩 처리 및 부분적인 게임 월드 시뮬레이션을 수행합니다. 서버는 핵심 게임 로직, 데이터 팩 및 게임 월드의 실제 상태를 유지합니다.
클라이언트는 서버의 월드를 부분적으로 복제하여, 다음과 같은 객체들의 복사본을 포함합니다:
net.minecraft.world.World net.minecraft.entity.Entity net.minecraft.block.entity.BlockEntity이 복제된 객체들은 클라이언트와 서버가 일부 공통 게임 로직을 수행할 수 있게 합니다. 클라이언트는 이 객체들과 상호작용할 수 있지만, 서버가 이들을 동기화하는 역할을 맡습니다. 보통 논리적 클라이언트의 객체와 논리적 서버의 객체를 구분하기 위해 객체의 월드를 접근하고
isClient
필드를 확인합니다. 이를 통해 서버에서 엔티티 생성 등의 권위적 행동을 수행하고, 클라이언트에서 행동을 시뮬레이션할 수 있습니다. 이 기법은 두 논리적 사이드 간의 비동기화를 방지하는 데 필수적입니다.
각 사이드에 대한 자세한 분석
이제 각 사이드가 무엇인지 이해했으니, 각각의 사이드를 자세히 살펴보겠습니다.
물리적 클라이언트
물리적 클라이언트는 바닐라 런처로 다운로드된 마인크래프트 jar 파일입니다. 여기에는 논리적 클라이언트와 논리적 서버(통합 서버)가 포함되어 있습니다. 진입점은 net.minecraft.client.main.Main
입니다.
물리적 클라이언트는 여러 다른 월드를 로드할 수 있으며, 각 월드는 별도의 논리적 서버 내에서 실행되지만, 한 번에 하나만 가능합니다.
전용 서버(물리적 서버)의 논리적 서버와 비교할 때, 물리적 클라이언트의 논리적 서버(통합 서버)는 물리적 클라이언트의 논리적 클라이언트에 의해 제어될 수 있습니다(예: F3+T로 데이터 팩을 다시 로드하거나, 클라이언트를 종료하면 통합 서버도 종료됨). 또한 월드에 번들된 리소스 팩을 물리적 클라이언트의 논리적 클라이언트에 로드할 수 있습니다.
모든 논리적 클라이언트 콘텐츠는 물리적 클라이언트에만 독점적이므로 렌더링, 사운드 및 기타 논리적 클라이언트 코드에 많은 환경 주석이 붙어 있는 것을 볼 수 있습니다.
일부 모드는 물리적 클라이언트를 독점적으로 타겟팅합니다. 예를 들어, Liteloader, Optifine 및 마인크래프트 PvP 클라이언트(Badlion, Hyperium) 등이 있습니다.
물리적 서버
물리적 서버는 자바 전용 서버입니다. 물리적 클라이언트와 비교할 때, 논리적 서버(전용 서버)만 있습니다. 진입점은 net.minecraft.server.MinecraftServer
이며, 물리적 서버는 실행 중 하나의 월드만 가질 수 있습니다. 서버가 다른 월드로 전환하려면 서버 재시작이 필요합니다.
논리적 서버는 물리적 클라이언트의 논리적 서버와 약간 다르며, 물리적 서버가 실행되는 동안 단 하나의 논리적 서버 인스턴스만 존재합니다. 게다가 물리적 서버의 논리적 서버는 Rcon을 통해 원격으로 제어할 수 있으며, server.properties라는 구성 파일이 있고, 서버 리소스 팩을 전송할 수 있습니다.
이러한 차이에도 불구하고, 대부분의 모드는 논리적 클라이언트 콘텐츠를 참조하지 않는 한 물리적 클라이언트와 물리적 서버의 논리적 서버에서 문제없이 작동할 수 있습니다.
단일 월드 및 리소스 팩 전송 기능 덕분에, 바닐라 모드(데이터 팩 및 리소스 팩 결합) 설치는 클라이언트보다 서버에서 훨씬 쉽습니다. 바닐라 물리적 클라이언트는 서버에 연결할 때 자동으로 설정됩니다.
일부 모드는 물리적 서버를 독점적으로 타겟팅합니다. 예를 들어, Bukkit과 그 파생물(Spigot, Paper, Cauldron, Xxx-Bukkit 하이브리드)은 항상 물리적 서버에서 실행됩니다.
논리적 클라이언트
논리적 클라이언트는 플레이어와의 인터페이스입니다. 렌더링(LWJGL), 리소스 팩, 플레이어 입력 처리, 사운드가 논리적 클라이언트에서 이루어집니다. 물리적 서버에는 존재하지 않습니다.
논리적 서버
논리적 서버는 대부분의 게임 로직이 실행되는 곳입니다. 데이터 팩, 월드 업데이트, 블록 엔티티 및 엔티티 틱, 몹 AI, 게임/월드 저장 및 월드 생성이 논리적 서버에서 이루어집니다.
물리적 클라이언트의 논리적 서버는 “통합 서버”라고 불리며, 물리적 서버의 논리적 서버는 “전용 서버”라고 불립니다(물리적 서버 자체의 이름이기도 함).
논리적 서버는 물리적 서버에서도 자체 메인 스레드에서 실행되며 몇 개의 작업 스레드를 갖습니다. 논리적 서버의 수명은 호스팅되는 물리적 사이드에 따라 달라집니다. 물리적 서버에서는 프로세스가 실행되는 한 논리적 서버가 존재합니다. 물리적 클라이언트에서는 여러 개의 논리적 서버가 생성될 수 있지만, 한 번에 하나의 논리적 서버만 존재할 수 있습니다. 플레이어가 로컬 저장 데이터를 로드하면 새로운 논리적 서버가 생성되고, 플레이어가 로컬 저장 데이터를 닫으면 논리적 서버가 종료됩니다.
대부분의 범용 모드는 싱글 플레이어와 멀티 플레이어 시나리오 모두에서 작동할 수 있도록 논리
적 서버를 타겟팅합니다.
통신
논리적 클라이언트와 서버 간에 데이터를 교환하는 유일한 올바른 방법은 패킷을 교환하는 것입니다. 패킷은 논리적 클라이언트와 논리적 서버 간에 전송되며, 물리적 사이드 간에 전송되지 않습니다. 모드는 두 논리적 사이드 간에 사용자 정의 정보를 전송하기 위해 패킷을 추가할 수 있습니다. 논리적 클라이언트가 자체 통합 서버에 연결된 경우 패킷은 메모리 내에서 교환되고, 그렇지 않으면 네트워크 프로토콜을 통해 교환됩니다.
논리적 클라이언트는 논리적 서버에 C2S(Client-To-Server) 패킷을 보냅니다. 논리적 서버는 논리적 클라이언트에 S2C(Server-To-Client) 패킷을 보냅니다. 패킷은 네트워크 스레드에서 쓰기 메서드를 통해 전송되고, 네트워크 스레드에서 읽기 메서드를 호출하여 수신됩니다.
네트워킹 처리 방법에 대한 자세한 내용은 이 기사를 참조하세요.
논리적 서버에 대한 일반적인 오해
대부분의 경우, 물리적 서버를 독점적으로 타겟팅하는 모드도 물리적 클라이언트 내의 논리적 서버에서 작동합니다.
그러나 물리적 서버 모더는 통합 서버에 적용되지 않는 가정을 하는 경우가 많습니다. 여기에는 다음이 포함되지만 이에 국한되지 않습니다:
- 하나의 게임 실행에서 하나의 논리적 서버 인스턴스만 존재한다.
- 월드와 엔티티는 항상 게임 로직을 계산해야 한다(즉, 월드 객체의 isClient 필드는 항상 false여야 한다).
- 원격 제어, 리소스 팩 전송 및 파비콘이 존재해야 한다.
이러한 가정은 논리적 서버에서 실행되는 모드를 만들기 위해 수정되어야 합니다.
결론
물리적 및 논리적 사이드의 가능한 조합:
논리적 클라이언트 | 논리적 서버 | |
---|---|---|
물리적 클라이언트 | 단일 인스턴스 항상 존재 | 로컬 저장 데이터 시 존재; 각 플레이 시 새로운 인스턴스 |
물리적 서버 | 존재하지 않음 | 단일 인스턴스 항상 존재 |
결국, 주된 혼란은 논리적 서버가 물리적 클라이언트에 존재한다는 사실에서 비롯됩니다.