feat: LAN 최대 인원 8 → 30 (단일 jar, 확장 불가 버전은 8 유지)
Some checks failed
build / build (push) Has been cancelled

바닐라 "LAN 에 공개" 의 상수 8 을 믹스인 1개로 30 으로 바꾼다. 대상과 메서드를
문자열로만 적고 핸들러를 int -> int 로 만들어 마인크래프트 타입 참조 0 을 유지한다.

8 이 있는 자리 (바닐라 jar 바이트코드 실측, 버전마다 정확히 한 곳):
- 1.17 ~ 1.21.8   class_1130.<init> (super 인자 → PlayerList.maxPlayers)
- 1.21.9 ~ 1.21.11 class_1132.method_3802 (return 8)
- 26.1 ~ 26.3     IntegratedServer.getMaxPlayers (공식 이름)

@Pseudo + require=0 이라 자리를 못 찾는 버전은 크래시 없이 바닐라 8 로 돈다.
적용 여부는 웹 콘솔 "최대 인원" 과 로그로 보인다.

tools/lan-limit-probe: 바닐라 jar + Fabric Loader 로 모드를 실제 로드해 확인하는 도구.
1.18.2 ~ 26.3 (11개 버전, 로더 0.19.5 / 0.14.25) 전부 30, 믹스인을 뺀 jar 는 8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-10-05 04:07:06 +09:00
parent 40b8894a98
commit 16a44ec4bc
13 changed files with 476 additions and 12 deletions

View File

@@ -3,7 +3,7 @@
초대코드 하나로 싱글플레이 월드를 친구와 함께 플레이하는 마인크래프트 P2P 모드.
**jar 파일 하나가 모든 마인크래프트 버전에서 동작한다.** 1.21 용, 1.21.8 용, 26.3 용을 따로
내려받지 않는다. 버전별 빌드도, 매핑도, 믹스인도 없다. 어떻게 가능한지는
내려받지 않는다. 버전별 빌드도, 매핑도 없다. 어떻게 가능한지는
[docs/DESIGN.md](docs/DESIGN.md) 에 근거와 함께 적어 두었다.
| | |
@@ -12,7 +12,8 @@
| 네이티브 라이브러리 | 0개 |
| jar 크기 | 약 0.71 MB |
| 지원 버전 | Fabric 이 도는 모든 버전 (JVM 17 이상) |
| 믹스인 | 없음 |
| 최대 인원 | 30명 (확장할 수 없는 버전은 바닐라 8명) |
| 믹스인 | 1개 — LAN 최대 인원 전용, 안 맞으면 스스로 빠진다 |
| 마인크래프트 클래스 참조 | 0개 (테스트로 강제) |
---
@@ -27,8 +28,8 @@
[mc_p2p] 준비 완료 — 조작은 http://127.0.0.1:25585 에서 한다
```
Fabric API 는 필요하지 않다. 다른 모드와 충돌할 여지도 사실상 없다 — 이 모드는 게임 코드를
한 줄도 건드리지 않는다.
Fabric API 는 필요하지 않다. 게임 코드에서 건드리는 곳은 "LAN 에 공개" 의 최대 인원 상수
하나뿐이다(아래 "최대 인원").
---
@@ -93,6 +94,37 @@ P2P 방 · 직결 23ms
---
## 최대 인원
바닐라 "LAN 에 공개" 는 8명으로 막혀 있다. 이 모드는 그걸 **30명**으로 올린다. 호스트 쪽
모드만 일하면 되고 설정할 것은 없다.
버전마다 8 이 박힌 자리가 달라서, jar 하나에 알려진 자리를 전부 넣어 두고 실행 중인 버전에
있는 자리만 바꾼다.
| 버전 | 8 이 있는 곳 | 결과 |
|---|---|---|
| 1.17 ~ 1.21.8 | `IntegratedPlayerList` 생성자 → `PlayerList.maxPlayers` | 30명 |
| 1.21.9 ~ 1.21.11 | `IntegratedServer.getMaxPlayers()` | 30명 |
| 26.1 ~ 26.3 | `IntegratedServer.getMaxPlayers()` (공식 이름) | 30명 |
| 그 밖의 미래 버전 | 자리가 바뀌었을 수 있음 | 못 찾으면 **8명** 으로 그대로 동작 |
자리를 못 찾아도 게임은 크래시하지 않는다. 확장만 빠지고 바닐라 8명으로 돈다. 실제로 적용됐는지는
웹 콘솔의 **최대 인원** 칸과 로그로 확인한다.
```
[mc_p2p] LAN 최대 인원을 8 → 30 명으로 올렸다
```
게임 로그 맨 앞에 아래 같은 `WARN` 이 한두 줄 찍히는 것은 정상이다. 다른 버전용 대상 이름을
찾다가 없다고 알리는 것이다(1.21.x 에서는 `IntegratedServer`, 26.x 에서는 `class_1130`/`class_1132`).
```
[main/WARN]: Error loading class: net/minecraft/client/server/IntegratedServer (java.lang.ClassNotFoundException: ...)
```
---
## 연결 방식
경로를 동시에 시도해서 되는 것을 쓴다.
@@ -165,7 +197,7 @@ Fabric Loom 을 쓰지 않으므로 마인크래프트를 내려받지 않고
솔직하게 적는다.
**기계로 확인된 것** (`./gradlew test`, 57개):
**기계로 확인된 것** (`./gradlew test`, 59개):
- 터널 전 구간 — 펀칭 프로브, 경로 선택, QUIC 핸드셰이크, 인증서 지문 고정, 방 비밀 대조,
TCP↔QUIC 양방향 운반. 직결과 중계 양쪽 모두 실제 소켓으로 왕복한다.
@@ -176,13 +208,22 @@ Fabric Loom 을 쓰지 않으므로 마인크래프트를 내려받지 않고
- LAN 비콘을 실제 멀티캐스트로 쏘고 받아 포트를 읽는다.
- 시그널링 프로토콜 — 등록, 참가, 방 중복, 호스트 이탈 시 방 정리, 잘못된 입력.
- 웹 콘솔 — 실제 HTTP 요청/응답, 루프백 전용 바인딩.
- **마인크래프트 클래스 참조 0개** — 컴파일된 클래스의 상수 풀을 뒤져서 강제한다.
- **마인크래프트 클래스 참조 0개** — 컴파일된 클래스의 상수 풀을 뒤져서 강제한다. 믹스인도
대상을 문자열로만 적고 게임 타입 서술자를 갖지 않는다는 것까지 검사한다.
**실제 Fabric 로더 위에서 확인된 것** (`tools/lan-limit-probe`):
- 바닐라 클라이언트 jar + Fabric Loader 로 모드를 실제로 로드해 최대 인원 믹스인이 적용되는지
본다. 1.18.2 · 1.20.1 · 1.21.1 · 1.21.8 · 1.21.9 · 1.21.11 · 26.1 · 26.3 전부 30.
1.21.9 이상은 `getMaxPlayers()` 를 직접 호출해 30 을 받았고, 1.21.8 이하는 생성된
`PlayerList` 의 `maxPlayers` 필드가 30 이다. 로더 0.19.5, 그리고 하한인 0.14.25(1.18.2·1.20.1).
**아직 확인되지 않은 것:**
- 실제 마인크래프트 클라이언트로 접속해 본 검증. 루프백 테스트는 프로토콜 계층까지만 본다.
- 실제 NAT 를 넘는 홀펀칭 성공률. 테스트는 같은 기기 안이라 NAT 가 없다.
- 1.21.x 와 26.x 양쪽에서의 실제 로드 확인.
- 화면을 띄운 실제 게임에서의 전체 흐름. 위 검증은 게임 메인 직전(preLaunch)에서 멈춘다.
최대 인원도 "판정에 쓰이는 값이 30" 까지 봤고, 실제로 9번째 이후 플레이어를 접속시켜 보지는 않았다.
---