267 lines
14 KiB
Markdown
267 lines
14 KiB
Markdown
# L2J Mobius High Five — Docker
|
||
|
||
L2J Mobius (хроники High Five, `L2J_Mobius_CT_2.6_HighFive`) в Docker Compose.
|
||
Три контейнера: `mysql`, `loginserver`, `gameserver`. Исходники сервера лежат
|
||
прямо в этом репозитории (`src/`) и собираются локально через Ant — без
|
||
внешних зависимостей от GitLab при каждой пересборке.
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
l2j-docker/
|
||
├── src/ # Исходники L2J Mobius (java/, build.xml, dist/, launcher/) — редактируешь напрямую
|
||
├── Dockerfile.build # Собирает src/ через Ant, кладёт результат в /out
|
||
├── scripts/
|
||
│ ├── collect-dist.sh # Нормализует результат сборки в /out/login, /out/game, /out/sql
|
||
│ └── extract-reference.sh # Выгружает /out на хост в reference/ для просмотра
|
||
├── login/
|
||
│ ├── Dockerfile # Runtime-образ login-сервера (JRE)
|
||
│ └── entrypoint.sh # Ждёт mysql, применяет config_override, стартует jar
|
||
├── game/
|
||
│ ├── Dockerfile # Runtime-образ game-сервера (JDK — нужен для скриптового движка)
|
||
│ └── entrypoint.sh # Ждёт mysql+login, применяет config_override, стартует jar
|
||
├── mysql/
|
||
│ ├── Dockerfile # MySQL 8.0 + автоимпорт SQL-схем при первом старте
|
||
│ └── init/
|
||
├── config/
|
||
│ ├── login/config/ # Override-конфиги login (применяются при каждом старте контейнера)
|
||
│ └── game/config/ # Override-конфиги game
|
||
├── reference/ # Сгенерированный полный дефолтный дистрибутив (не в git, см. ниже)
|
||
├── geodata/ # .l2j файлы геодаты (не входят в репозиторий, кладутся руками)
|
||
├── docker-compose.yml
|
||
├── .env # Пароли, порты — реальные значения, не в git
|
||
└── .env.example # Шаблон .env с плейсхолдерами
|
||
```
|
||
|
||
## Как это работает
|
||
|
||
1. **`Dockerfile.build`** копирует `src/` в builder-образ и собирает его через
|
||
`ant -f build.xml`. Результат — `LoginServer.jar`, `GameServer.jar` и SQL-схемы.
|
||
2. **`scripts/collect-dist.sh`** раскладывает собранный архив в `/out/login`,
|
||
`/out/game`, `/out/sql` — единую структуру для runtime-образов.
|
||
3. **`login/Dockerfile`** и **`game/Dockerfile`** берут готовый `/out/*` из
|
||
builder-образа и кладут в финальный контейнер с JRE/JDK.
|
||
4. **`config/login/config/`** и **`config/game/config/`** — это **единственное
|
||
место, где нужно редактировать конфиги**. При каждом старте контейнера
|
||
`entrypoint.sh` копирует всё из этой папки поверх дефолтных файлов внутри
|
||
контейнера. Правки здесь переживают любой `docker compose build` /
|
||
`--force-recreate`. Редактировать конфиги внутри уже запущенного
|
||
контейнера (`docker exec`) — не сохранится после пересборки.
|
||
|
||
## Запуск с нуля
|
||
|
||
### 1. Собрать builder-образ
|
||
|
||
```bash
|
||
docker build -f Dockerfile.build -t l2j-build:latest .
|
||
```
|
||
|
||
### 2. Геодата
|
||
|
||
Скачай геодату для High Five отдельно. (Можно [тут](https://git.poisonflower.ru/poison-flower/l2-h5-geodata/src/branch/main))
|
||
Распакуй все `.l2j` файлы (и `geo_index.txt`) прямо в `./geodata/`, без
|
||
вложенных подпапок.
|
||
|
||
### 3. Настроить `.env`
|
||
|
||
```bash
|
||
cp .env.example .env # если только клонировал репозиторий
|
||
nano .env
|
||
```
|
||
|
||
Задай `MYSQL_ROOT_PASSWORD` и остальные значения. **Важно**: пароль здесь
|
||
должен совпадать с паролем в `config/login/config/Database.ini` и
|
||
`config/game/config/Database.ini` (см. ниже).
|
||
|
||
### ⚠️ Обязательно смени перед первым запуском
|
||
|
||
Репозиторий содержит рабочие сетевые настройки (`mysql`, `loginserver`
|
||
вместо `localhost`), но **пароль и IP — от конкретной машины, на которой
|
||
это разворачивалось изначально**. Смени их в трёх местах, иначе:
|
||
подключение к БД будет использовать чужой пароль, а клиенты будут
|
||
пытаться попасть на чужой IP.
|
||
|
||
1. **`config/login/config/Database.ini`** и **`config/game/config/Database.ini`**
|
||
— строка `Password = ...`. Должна совпадать с `MYSQL_ROOT_PASSWORD` в
|
||
`.env`.
|
||
2. **`config/game/config/ipconfig.xml`** — атрибут `address="..."` в
|
||
корневом теге `<gameserver>`. Это IP/домен, который сервер сообщает
|
||
клиенту после выбора сервера в списке (свой локальный/публичный IP,
|
||
не `192.168.1.207` — это чужая машина).
|
||
|
||
Всё остальное (`mysql`, `loginserver`, `0.0.0.0` в `Server.ini`) —
|
||
универсальные значения, менять не нужно, они завязаны на имена сервисов
|
||
в `docker-compose.yml`, а не на конкретный хост.
|
||
|
||
### 4. Настроить сетевые конфиги
|
||
|
||
Login и game сервера по умолчанию слушают/подключаются на `localhost` —
|
||
внутри Docker-сети это не работает, контейнеры видят друг друга по именам
|
||
сервисов (`mysql`, `loginserver`, `gameserver`). Уже настроено в
|
||
`config/*/config/Database.ini` и `config/login/config/Server.ini`:
|
||
|
||
- `Database.ini` (оба сервера): `URL = jdbc:mysql://mysql/l2jmobiush5?...`
|
||
- `login/config/Server.ini`: `LoginHostname = 0.0.0.0`, `LoginHostname` для
|
||
приёма game-сервера — `LoginHost = 0.0.0.0` (не `127.0.0.1`, иначе
|
||
gameserver не сможет подключиться из своего контейнера)
|
||
- `game/config/Server.ini`: `LoginHost = loginserver` (имя сервиса, не IP)
|
||
|
||
### 5. ipconfig.xml — адрес для клиентов
|
||
|
||
`config/game/config/ipconfig.xml` определяет, какой IP-адрес game-сервер
|
||
сообщает клиенту после выбора сервера в списке. Если клиент подключается:
|
||
|
||
- **с этого же сервера** — оставь `127.0.0.1`
|
||
- **из локальной сети** — укажи локальный IP сервера (например, `192.168.1.207`)
|
||
- **из интернета** — укажи публичный IP или домен
|
||
|
||
Пример минимального конфига:
|
||
|
||
```xml
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<gameserver address="192.168.1.207" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../data/xsd/ipconfig.xsd">
|
||
</gameserver>
|
||
```
|
||
|
||
### 6. Собрать и запустить
|
||
|
||
```bash
|
||
docker compose build
|
||
docker compose up -d
|
||
docker compose logs -f mysql loginserver gameserver
|
||
```
|
||
|
||
Ожидаемая последовательность в логах:
|
||
1. `mysql` — выполняет SQL-схемы, проходит healthcheck
|
||
2. `loginserver` — `LoginServer: Login client listener started on 0.0.0.0:2106`
|
||
3. `gameserver` — `LoginServerThread: Registered on login as Server N: <Name>`
|
||
|
||
Если видишь `Registered on login as Server` — стек полностью поднят.
|
||
|
||
## Просмотр полного дистрибутива сервера (reference)
|
||
|
||
`/out` внутри builder-образа (`login/`, `game/`, `sql/` с jar-файлами,
|
||
конфигами и data/) существует только как промежуточный слой между стадиями
|
||
Docker-сборки — на хосте его не видно напрямую. Чтобы удобно читать
|
||
дефолтные файлы сервера (посмотреть, что там есть, прежде чем что-то
|
||
копировать в override), используй скрипт `scripts/extract-reference.sh`:
|
||
|
||
```bash
|
||
./scripts/extract-reference.sh
|
||
```
|
||
|
||
Это выгружает полный `/out` из свежего `l2j-build:latest` образа в
|
||
`./reference/` — обычную папку на диске:
|
||
|
||
```
|
||
reference/login/config/...
|
||
reference/game/config/...
|
||
reference/game/data/...
|
||
reference/login/libs/...
|
||
```
|
||
|
||
Дальше — смотришь нужный файл и копируешь **только его** в override:
|
||
|
||
```bash
|
||
cat reference/game/config/Rates.ini
|
||
cp reference/game/config/Rates.ini config/game/config/Rates.ini
|
||
nano config/game/config/Rates.ini
|
||
docker compose up -d --force-recreate gameserver
|
||
```
|
||
|
||
`reference/` — сгенерированные файлы, не нужно коммитить их в git (см.
|
||
`.gitignore`). После пересборки Java-кода (`docker build -f Dockerfile.build
|
||
...`) перезапусти скрипт, чтобы `reference/` отражал актуальную сборку:
|
||
|
||
```bash
|
||
docker build -f Dockerfile.build -t l2j-build:latest . && ./scripts/extract-reference.sh
|
||
```
|
||
|
||
## Редактирование конфигов
|
||
|
||
Все дефолтные конфиги обоих серверов уже скопированы в
|
||
`config/login/config/` и `config/game/config/`. Правь их прямо здесь:
|
||
|
||
```bash
|
||
nano config/game/config/Rates.ini # рейты экспы/дропа
|
||
nano config/game/config/NPC.ini # агрессия, respawn
|
||
nano config/game/config/Player.ini # лимиты персонажей
|
||
```
|
||
|
||
После правки — пересоздать нужный контейнер (без пересборки образа, если
|
||
менялся только конфиг, а не код):
|
||
|
||
```bash
|
||
docker compose up -d --force-recreate gameserver
|
||
```
|
||
|
||
**Важно — не копируй `reference/` в `config/` массово поверх уже
|
||
настроенных файлов.** `config/login/config/Database.ini`,
|
||
`config/game/config/Database.ini`, `config/game/config/Server.ini` и
|
||
`config/game/config/ipconfig.xml` содержат критичные сетевые правки
|
||
(`mysql`/`loginserver` вместо `localhost`/`127.0.0.1`) — если их затереть
|
||
дефолтными значениями из `reference/`, game-сервер перестанет находить
|
||
MySQL или login-сервер (`Connection refused`, `LoginServer not available`).
|
||
Копируй в override только конкретные файлы, которые собираешься менять,
|
||
не весь каталог целиком.
|
||
|
||
## Изменение кода сервера
|
||
|
||
Исходники лежат в `src/java/`. После правки:
|
||
|
||
```bash
|
||
docker build -f Dockerfile.build -t l2j-build:latest .
|
||
docker compose build
|
||
docker compose up -d
|
||
```
|
||
|
||
Первая команда пересобирает Java-код через Ant, вторая — пересобирает
|
||
runtime-образы login/game с новыми jar-файлами, третья — перезапускает стек.
|
||
|
||
## Память JVM
|
||
|
||
Размер кучи для game-сервера задан в `game/entrypoint.sh`:
|
||
|
||
```bash
|
||
exec java -Xms1g -Xmx4g -Dfile.encoding=UTF-8 -cp "$CLASSPATH" -jar libs/GameServer.jar
|
||
```
|
||
|
||
Полная геодата High Five (203 региона) требует заметного объёма памяти при
|
||
загрузке — при `OutOfMemoryError` на этапе `[ Geodata ]` увеличь `-Xmx`.
|
||
После правки:
|
||
|
||
```bash
|
||
docker compose build gameserver
|
||
docker compose up -d --force-recreate gameserver
|
||
```
|
||
|
||
## Резервное копирование
|
||
|
||
Образы и контейнеры полностью воспроизводимы из этого репозитория — бэкапить
|
||
нужно только:
|
||
|
||
1. **Сам репозиторий** (`src/`, конфиги, override) — обычный git.
|
||
2. **Данные MySQL** (аккаунты, персонажи) — они живут в Docker-volume
|
||
`mysql_data`, не в файлах проекта. Дамп:
|
||
|
||
```bash
|
||
docker exec l2j-mysql mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" l2jmobiush5 > backup_$(date +%Y%m%d_%H%M%S).sql
|
||
```
|
||
|
||
Восстановление:
|
||
|
||
```bash
|
||
docker exec -i l2j-mysql mysql -u root -p"$MYSQL_ROOT_PASSWORD" l2jmobiush5 < backup_ФАЙЛ.sql
|
||
```
|
||
|
||
## Порты
|
||
|
||
| Сервис | Порт | Назначение |
|
||
|---|---|---|
|
||
| loginserver | 2106 | Подключение клиента (экран логина) |
|
||
| gameserver | 7777 | Подключение клиента (после выбора сервера) |
|
||
| gameserver → loginserver | 9014 | Внутренний auth-обмен между серверами |
|
||
| mysql | 3306 | БД (не публикуется наружу по умолчанию) |
|
||
|
||
Меняются в `.env`.
|