Add Essence 520 minimal DB, configs, and login/game Docker profile.

This commit is contained in:
test
2026-05-18 12:54:47 +03:00
parent a4a3a2aa09
commit 6fdbc9b103
21 changed files with 438 additions and 172 deletions
+14 -4
View File
@@ -1,9 +1,19 @@
# Скопируйте в .env (install.sh создаст .env сам).
# В паролях для docker compose символ $ нужно удваивать: pa$$word
# PostgreSQL
POSTGRES_USER=l2user
POSTGRES_PASSWORD=change_me_strong_password
POSTGRES_DB=l2essence
POSTGRES_PORT=5432
# Образ игрового сервера (когда будет свой реестр/локальная сборка)
# L2_SERVER_IMAGE=your-registry/l2-essence-542:latest
# Клиент Essence protocol 520
L2_PROTOCOL=520
# Порты (профиль docker compose --profile l2)
L2_LOGIN_PORT=2106
L2_LOGIN_GS_PORT=9014
L2_GAME_PORT=7777
# Образы Java для Login/Game (если используете profile l2)
# L2_LOGIN_IMAGE=eclipse-temurin:21-jre
# L2_GAME_IMAGE=eclipse-temurin:21-jre
# В паролях для docker compose символ $ удваивайте: pa$$word
+24
View File
@@ -0,0 +1,24 @@
# Lineage 2 Essence — Game Server (шаблон, клиент protocol 520)
# Скопируйте в dist/game/config/ вашей сборки.
LoginHost = login
LoginPort = 9014
GameserverHostname = *
GameserverPort = 7777
RequestServerID = 1
AcceptAlternateID = True
MaximumOnlineUsers = 500
DatapackRoot = .
# Только клиент 520 (Essence)
AllowedProtocolRevisions = 520
Driver = org.postgresql.Driver
URL = jdbc:postgresql://postgres:5432/l2essence
Login = l2user
Password = change_me_strong_password
MaximumDbConnections = 100
CharMaxNumber = 7
CnameTemplate = .*
+3
View File
@@ -0,0 +1,3 @@
# HexID = RequestServerID 1 (должен совпадать с gameservers.hexid в БД)
HexID=a1b2c3d4e5f6789012345678901234ef
ServerID=1
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../data/xsd/ipconfig.xsd">
<host subnet="0.0.0.0/0" address="127.0.0.1" />
</list>
+24
View File
@@ -0,0 +1,24 @@
# Lineage 2 Essence — Login Server (шаблон под Docker + PostgreSQL 17)
# Скопируйте в dist/login/config/ вашей сборки Samurai Crow / Mobius Essence.
LoginserverHostname = *
LoginserverPort = 2106
LoginHostname = 0.0.0.0
LoginPort = 9014
LoginTryBeforeBan = 5
LoginBlockAfterBan = 900
AcceptNewGameServer = True
EnableFloodProtection = True
AutoCreateAccounts = True
ShowLicence = False
# PostgreSQL (хост postgres — имя сервиса в docker-compose)
Driver = org.postgresql.Driver
URL = jdbc:postgresql://postgres:5432/l2essence
Login = l2user
Password = change_me_strong_password
MaximumDbConnections = 50
DatapackRoot = .
Debug = False
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../data/xsd/ipconfig.xsd">
<!-- Внешний IP для клиента (замените на IP вашего VPS) -->
<host subnet="0.0.0.0/0" address="127.0.0.1" />
</list>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<servers>
<server id="1" name="Essence 520" />
</servers>
+35 -16
View File
@@ -1,5 +1,5 @@
# Lineage 2 Essence 542 (Samurai Crow) — локальная среда
# Замените сервис l2-server на свой образ/сборку, когда будет готов Dockerfile.
# Lineage 2 Essence — клиент protocol 520, PostgreSQL 17
# БД: login + game в одной БД. JAR Login/Game — в ./server (см. config/).
services:
postgres:
@@ -22,23 +22,42 @@ services:
timeout: 5s
retries: 10
# Заглушка: подключите свой сервер (Auth/Game) или замените build: на реальный Dockerfile.
l2-server:
image: ${L2_SERVER_IMAGE:-ubuntu:24.04}
container_name: l2_server_placeholder
restart: "no"
# Подключите сборку Samurai Crow / Mobius Essence (520):
# положите login/game в ./server/login и ./server/game, раскомментируйте сервисы.
login:
profiles: ["l2"]
image: ${L2_LOGIN_IMAGE:-eclipse-temurin:21-jre}
container_name: l2_login
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-l2user}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-l2essence}
# Раскомментируйте при готовности бинарей/скриптов:
# volumes:
# - ./server:/opt/l2server:ro
# command: ["/opt/l2server/start.sh"]
command: ["bash", "-lc", "echo 'L2 server placeholder: замените сервис l2-server в docker-compose.yml'; sleep infinity"]
profiles:
- placeholder
working_dir: /opt/l2/login
volumes:
- ./server/login:/opt/l2/login
- ./config/login:/opt/l2/login/config:ro
ports:
- "${L2_LOGIN_PORT:-2106}:2106"
- "${L2_LOGIN_GS_PORT:-9014}:9014"
command: ["bash", "-lc", "test -f ./LoginServer.jar && java -jar LoginServer.jar || echo 'Нет LoginServer.jar в server/login'; sleep infinity"]
game:
profiles: ["l2"]
image: ${L2_GAME_IMAGE:-eclipse-temurin:21-jre}
container_name: l2_game
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
login:
condition: service_started
working_dir: /opt/l2/game
volumes:
- ./server/game:/opt/l2/game
- ./config/game:/opt/l2/game/config:ro
ports:
- "${L2_GAME_PORT:-7777}:7777"
command: ["bash", "-lc", "test -f ./GameServer.jar && java -jar GameServer.jar || echo 'Нет GameServer.jar в server/game'; sleep infinity"]
volumes:
postgres_data:
+38
View File
@@ -0,0 +1,38 @@
-- Login DB: L2J Mobius / Essence (совместимость с клиентом protocol 520).
-- Пароль: Base64(SHA1(UTF-8 пароль)) — см. LoginController Mobius.
CREATE TABLE IF NOT EXISTS accounts (
login VARCHAR(45) NOT NULL PRIMARY KEY,
password VARCHAR(45),
lastactive BIGINT,
"accessLevel" INTEGER NOT NULL DEFAULT 0,
"lastIP" VARCHAR(20),
"lastServer" INTEGER DEFAULT 1,
"pcIp" VARCHAR(20),
hop1 VARCHAR(20),
hop2 VARCHAR(20),
hop3 VARCHAR(20),
hop4 VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS account_data (
account_name VARCHAR(45) NOT NULL,
var VARCHAR(20) NOT NULL,
value VARCHAR(255),
PRIMARY KEY (account_name, var),
CONSTRAINT fk_account_data_login FOREIGN KEY (account_name)
REFERENCES accounts (login) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS accounts_ipauth (
login VARCHAR(45) NOT NULL,
ip VARCHAR(15) NOT NULL,
type VARCHAR(15) NOT NULL,
PRIMARY KEY (login, ip)
);
CREATE TABLE IF NOT EXISTS gameservers (
server_id INTEGER NOT NULL PRIMARY KEY,
hexid VARCHAR(50) NOT NULL,
host VARCHAR(50) NOT NULL
);
-49
View File
@@ -1,49 +0,0 @@
-- Минимальные таблицы под логин-сервер в стиле L2J (accounts / gameservers / account_data).
-- Подходит для многих форков; у Samurai Crow/Essence могут отличаться имена колонок или хеш пароля —
-- тогда сверьте с SQL из вашей сборки и поправьте этот файл.
--
-- Тестовый логин: admin / admin
-- Хеш: Base64(SHA1 от UTF-8 строки «admin») — типично для L2J/Mobius.
-- Альтернатива (если сборка ждёт hex SHA1): замените поле password на
-- d033e22ae348aeb5660fc2140aec35850c4da997
CREATE TABLE IF NOT EXISTS accounts (
login VARCHAR(45) NOT NULL PRIMARY KEY,
password VARCHAR(128),
lastactive BIGINT,
accesslevel INTEGER NOT NULL DEFAULT 0,
lastip VARCHAR(45),
lastserver SMALLINT DEFAULT 1
);
CREATE TABLE IF NOT EXISTS account_data (
account_name VARCHAR(45) NOT NULL,
var VARCHAR(50) NOT NULL,
value VARCHAR(255),
PRIMARY KEY (account_name, var),
CONSTRAINT fk_account_data_account FOREIGN KEY (account_name)
REFERENCES accounts (login) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS gameservers (
hexid VARCHAR(255) NOT NULL,
server_id INTEGER NOT NULL PRIMARY KEY,
host VARCHAR(255) NOT NULL
);
INSERT INTO accounts (login, password, lastactive, accesslevel, lastip, lastserver)
VALUES (
'admin',
'0DPiKuNIrrVmD8IUCuw1hQxNqZc=',
(EXTRACT(EPOCH FROM NOW()) * 1000)::bigint,
0,
'127.0.0.1',
1
)
ON CONFLICT (login) DO NOTHING;
-- Игровой сервер при первом подключении к логину часто сам делает INSERT в gameservers.
-- Если нужна явная запись (hexid должен совпасть с RequestServerID / hex в конфиге GS):
-- INSERT INTO gameservers (hexid, server_id, host)
-- VALUES ('ВАШ_32_СИМВОЛА_HEX', 1, '127.0.0.1')
-- ON CONFLICT (server_id) DO UPDATE SET hexid = EXCLUDED.hexid, host = EXCLUDED.host;
@@ -0,0 +1,139 @@
-- Game DB (та же БД): минимум для экрана выбора/создания персонажа и входа в мир.
-- Полный дамп datapack ставьте поверх, если сборка Samurai Crow требует больше таблиц.
CREATE TABLE IF NOT EXISTS global_data (
var VARCHAR(255) NOT NULL PRIMARY KEY,
value TEXT
);
CREATE TABLE IF NOT EXISTS characters (
account_name VARCHAR(45),
charId INTEGER NOT NULL PRIMARY KEY,
char_name VARCHAR(35) NOT NULL,
level SMALLINT DEFAULT 1,
maxHp INTEGER DEFAULT 100,
curHp INTEGER DEFAULT 100,
maxCp INTEGER DEFAULT 100,
curCp INTEGER DEFAULT 100,
maxMp INTEGER DEFAULT 100,
curMp INTEGER DEFAULT 100,
face SMALLINT DEFAULT 0,
hairStyle SMALLINT DEFAULT 0,
hairColor SMALLINT DEFAULT 0,
sex SMALLINT DEFAULT 0,
reputation INTEGER DEFAULT 0,
fame INTEGER DEFAULT 0,
raidbossPoints INTEGER DEFAULT 0,
pvpkills INTEGER DEFAULT 0,
pkkills INTEGER DEFAULT 0,
clanid INTEGER DEFAULT 0,
race SMALLINT DEFAULT 0,
classid INTEGER DEFAULT 0,
deletetime BIGINT DEFAULT 0,
title VARCHAR(21) DEFAULT '',
accesslevel INTEGER DEFAULT 0,
online SMALLINT DEFAULT 0,
onlinetime INTEGER DEFAULT 0,
char_slot SMALLINT DEFAULT 0,
lastAccess BIGINT DEFAULT 0,
clan_privs INTEGER DEFAULT 0,
wantspeace SMALLINT DEFAULT 0,
base_class INTEGER DEFAULT 0,
x INTEGER DEFAULT -114520,
y INTEGER DEFAULT -249704,
z INTEGER DEFAULT -2984,
heading INTEGER DEFAULT 0,
createDate DATE DEFAULT CURRENT_DATE,
isIn7sDungeon SMALLINT DEFAULT 0,
in_jail SMALLINT DEFAULT 0,
jail_timer INTEGER DEFAULT 0,
powerGrade SMALLINT DEFAULT 0,
apprentice INTEGER DEFAULT 0,
sponsor INTEGER DEFAULT 0,
clan_join_expiry_time TIMESTAMP NULL,
clan_create_expiry_time TIMESTAMP NULL,
bookmarkslot SMALLINT DEFAULT 0,
vitality_points INTEGER DEFAULT 35000,
language VARCHAR(5) DEFAULT 'en'
);
CREATE INDEX IF NOT EXISTS idx_characters_account ON characters (account_name);
CREATE UNIQUE INDEX IF NOT EXISTS idx_characters_name ON characters (char_name);
CREATE TABLE IF NOT EXISTS character_subclasses (
charId INTEGER NOT NULL,
class_id INTEGER NOT NULL DEFAULT 0,
exp BIGINT DEFAULT 0,
sp BIGINT DEFAULT 0,
level INTEGER DEFAULT 1,
class_index INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (charId, class_index),
CONSTRAINT fk_subclasses_char FOREIGN KEY (charId)
REFERENCES characters (charId) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS character_skills (
charId INTEGER NOT NULL,
skill_id INTEGER NOT NULL,
skill_level INTEGER NOT NULL DEFAULT 1,
class_index INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (charId, skill_id, class_index),
CONSTRAINT fk_skills_char FOREIGN KEY (charId)
REFERENCES characters (charId) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS character_shortcuts (
charId INTEGER NOT NULL,
slot INTEGER NOT NULL,
page INTEGER NOT NULL,
type INTEGER DEFAULT 0,
shortcut_id INTEGER DEFAULT 0,
level INTEGER DEFAULT 0,
class_index INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (charId, slot, page, class_index),
CONSTRAINT fk_shortcuts_char FOREIGN KEY (charId)
REFERENCES characters (charId) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS character_variables (
charId INTEGER NOT NULL,
var VARCHAR(255) NOT NULL,
val TEXT,
PRIMARY KEY (charId, var),
CONSTRAINT fk_variables_char FOREIGN KEY (charId)
REFERENCES characters (charId) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS items (
object_id INTEGER NOT NULL PRIMARY KEY,
owner_id INTEGER NOT NULL,
item_id INTEGER NOT NULL,
count BIGINT NOT NULL DEFAULT 1,
enchant_level INTEGER DEFAULT 0,
loc VARCHAR(10) NOT NULL DEFAULT 'INVENTORY',
loc_data INTEGER DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_items_owner ON items (owner_id);
CREATE TABLE IF NOT EXISTS clan_data (
clan_id INTEGER NOT NULL PRIMARY KEY,
clan_name VARCHAR(45) NOT NULL,
clan_level INTEGER DEFAULT 0,
reputation_score INTEGER DEFAULT 0,
hasCastle INTEGER DEFAULT 0,
blood_alliance INTEGER DEFAULT 0,
blood_oath INTEGER DEFAULT 0,
ally_id INTEGER DEFAULT 0,
ally_name VARCHAR(45) DEFAULT '',
leader_id INTEGER DEFAULT 0,
crest_id INTEGER DEFAULT 0,
crest_large_id INTEGER DEFAULT 0,
ally_crest_id INTEGER DEFAULT 0,
auction_bid_at INTEGER DEFAULT 0,
ally_penalty_expiry_time BIGINT DEFAULT 0,
ally_penalty_type SMALLINT DEFAULT 0,
char_penalty_expiry_time BIGINT DEFAULT 0,
dissolving_expiry_time BIGINT DEFAULT 0,
new_leader_id INTEGER DEFAULT 0
);
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
# Выдаёт владельца таблиц логина роли из POSTGRES_USER (см. docker-compose).
set -eu
psql -v ON_ERROR_STOP=1 --username "postgres" --dbname "$POSTGRES_DB" <<-EOSQL
ALTER TABLE IF EXISTS accounts OWNER TO "${POSTGRES_USER}";
ALTER TABLE IF EXISTS account_data OWNER TO "${POSTGRES_USER}";
ALTER TABLE IF EXISTS gameservers OWNER TO "${POSTGRES_USER}";
EOSQL
+33
View File
@@ -0,0 +1,33 @@
-- Тестовые данные: Essence protocol 520 (логин + регистрация GS).
-- Логины: admin/admin, test/test
-- Hexid совпадает с server/hexid/default.txt
INSERT INTO global_data (var, value)
VALUES ('essence_protocol', '520')
ON CONFLICT (var) DO UPDATE SET value = EXCLUDED.value;
INSERT INTO accounts (login, password, lastactive, "accessLevel", "lastIP", "lastServer")
VALUES
(
'admin',
'0DPiKuNIrrVmD8IUCuw1hQxNqZc=',
(EXTRACT(EPOCH FROM NOW()) * 1000)::bigint,
100,
'127.0.0.1',
1
),
(
'test',
'qUqP5cyxm6YcTAhz05Hph5gvu9M=',
(EXTRACT(EPOCH FROM NOW()) * 1000)::bigint,
0,
'127.0.0.1',
1
)
ON CONFLICT (login) DO NOTHING;
-- RequestServerID = 1, hex из server/hexid/default.txt
INSERT INTO gameservers (server_id, hexid, host)
VALUES (1, 'a1b2c3d4e5f6789012345678901234ef', '127.0.0.1')
ON CONFLICT (server_id) DO UPDATE
SET hexid = EXCLUDED.hexid, host = EXCLUDED.host;
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
# Владелец всех таблиц public → POSTGRES_USER (после всех *.sql).
set -eu
psql -v ON_ERROR_STOP=1 --username "postgres" --dbname "$POSTGRES_DB" <<-EOSQL
DO \$\$
DECLARE
t text;
BEGIN
FOR t IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
LOOP
EXECUTE format('ALTER TABLE IF EXISTS %I OWNER TO %I', t, '${POSTGRES_USER}');
END LOOP;
END \$\$;
EOSQL
+18 -8
View File
@@ -50,8 +50,8 @@ read_env_val() {
# --- Шаг 0: приветствие ---
step_header "Шаг 0 — Обзор"
echo "Проект: Lineage 2 Essence 542 (Samurai Crow), окружение в Docker."
echo удет поднят PostgreSQL 17; игровой сервис — по профилю placeholder (заглушка), пока нет своего образа."
echo "Проект: Lineage 2 Essence, клиент protocol 520, PostgreSQL 17."
echo Д: login + game (минимум для входа). Login/Game JAR — профиль l2 (server/login, server/game)."
if ! ask_yes_no "Продолжить?" "y"; then
info "Выход."
exit 0
@@ -161,6 +161,7 @@ fi
step_header "Шаг 5 — Запуск PostgreSQL 17"
if ask_yes_no "Поднять только PostgreSQL (рекомендуется)?" "y"; then
chmod +x "$SCRIPT_DIR"/docker/initdb/*.sh 2>/dev/null || true
chmod +x "$SCRIPT_DIR"/scripts/*.sh 2>/dev/null || true
docker compose up -d postgres
info "Ожидание готовности PostgreSQL (pg_isready)..."
EV_USER="$(read_env_val POSTGRES_USER)"
@@ -174,11 +175,17 @@ if ask_yes_no "Поднять только PostgreSQL (рекомендуетс
docker compose ps
fi
# --- Шаг 6: заглушка L2 ---
step_header "Шаг 6 — Игровой контейнер (заглушка)"
warn "Сервис l2-server в compose помечен profile 'placeholder'. Замените образ/команду под Samurai Crow."
if ask_yes_no "Запустить контейнер-заглушку l2-server (для проверки сети к БД)?" "n"; then
docker compose --profile placeholder up -d l2-server
# --- Шаг 6: конфиг и Login/Game ---
step_header "Шаг 6 — Конфиг Essence 520"
if [[ -f "$SCRIPT_DIR/scripts/sync-config-password.sh" ]]; then
if ask_yes_no "Подставить пароль БД из .env в config/login и config/game?" "y"; then
bash "$SCRIPT_DIR/scripts/sync-config-password.sh"
fi
fi
step_header "Шаг 7 — Login / Game (Docker profile l2)"
warn "Положите LoginServer.jar и GameServer.jar в server/login и server/game."
if ask_yes_no "Запустить контейнеры login + game (profile l2)?" "n"; then
docker compose --profile l2 up -d login game
docker compose ps
fi
@@ -189,8 +196,11 @@ EV_DB="$(read_env_val POSTGRES_DB)"
EV_PORT="$(read_env_val POSTGRES_PORT)"
info "Строка подключения с хоста Ubuntu: postgresql://${EV_USER}:***@127.0.0.1:${EV_PORT}/${EV_DB}"
info "Из контейнеров в этой compose-сети: хост postgres, порт 5432."
info "Тест-аккаунты: admin/admin и test/test."
info "Клиент: protocol 520, логин 127.0.0.1:2106, мир 127.0.0.1:7777."
echo ""
info "Полезные команды:"
echo " docker compose logs -f postgres"
echo " docker compose --profile l2 up -d login game"
echo " ./scripts/apply-essence-schema.sh # если БД уже была без новых таблиц"
echo " docker compose down"
echo " docker compose --profile placeholder down"
+49 -87
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env bash
# Интерактивное управление: остановка, запуск, перезапуск Docker-сервисов проекта.
# Запуск: chmod +x manage.sh && ./manage.sh
# Управление: PostgreSQL + Login/Game (Essence 520, profile l2).
set -euo pipefail
@@ -13,10 +12,10 @@ YELLOW='\033[1;33m'
NC='\033[0m'
ENV_FILE="$SCRIPT_DIR/.env"
PROFILE_PLACEHOLDER=(--profile placeholder)
# Имена из docker-compose.yml (для надёжной проверки состояния)
PROFILE_L2=(--profile l2)
PG_CONTAINER="l2_postgres"
L2_CONTAINER="l2_server_placeholder"
LOGIN_CONTAINER="l2_login"
GAME_CONTAINER="l2_game"
read_env_val() {
local key="$1"
@@ -50,144 +49,107 @@ step_header() {
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}
require_cmd() {
command -v "$1" >/dev/null 2>&1
}
ensure_docker() {
if ! require_cmd docker || ! docker compose version >/dev/null 2>&1; then
err "Нужны Docker и плагин «docker compose». Установите через ./install.sh"
if ! command -v docker >/dev/null 2>&1 || ! docker compose version >/dev/null 2>&1; then
err "Нужны Docker и docker compose. Запустите ./install.sh"
exit 1
fi
if ! docker info >/dev/null 2>&1; then
err "Docker недоступен (sudo или перелогин после группы docker)."
err "Docker недоступен."
exit 1
fi
}
ensure_env() {
if [[ ! -f "$ENV_FILE" ]]; then
err "Нет файла .env. Сначала выполните ./install.sh"
err "Нет .env. Сначала ./install.sh"
exit 1
fi
}
postgres_running() {
[[ "$(docker inspect -f '{{.State.Running}}' "$PG_CONTAINER" 2>/dev/null || echo false)" == "true" ]]
container_running() {
[[ "$(docker inspect -f '{{.State.Running}}' "$1" 2>/dev/null || echo false)" == "true" ]]
}
l2_running() {
[[ "$(docker inspect -f '{{.State.Running}}' "$L2_CONTAINER" 2>/dev/null || echo false)" == "true" ]]
}
postgres_running() { container_running "$PG_CONTAINER"; }
login_running() { container_running "$LOGIN_CONTAINER"; }
game_running() { container_running "$GAME_CONTAINER"; }
# --- Шаг 0 ---
step_header "Шаг 0 — Управление сервером (Docker Compose)"
echo "Проект: PostgreSQL 17 + опционально l2-server (profile placeholder)."
step_header "Шаг 0 — Essence 520 (PostgreSQL + Login/Game)"
if ! ask_yes_no "Продолжить?" "y"; then
info "Выход."
exit 0
fi
ensure_docker
ensure_env
# --- Шаг 1: статус ---
step_header "Шаг 1 — Текущий статус"
step_header "Шаг 1Статус"
if ask_yes_no "Показать docker compose ps?" "y"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" ps -a || true
docker compose ps -a || true
docker compose "${PROFILE_L2[@]}" ps -a 2>/dev/null || true
fi
# --- Шаг 2: остановка ---
step_header "Шаг 2 — Остановка"
if ask_yes_no "Остановить контейнер l2-server (если был запущен с profile placeholder)?" "n"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" stop l2-server 2>/dev/null || warn "l2-server не остановлен (возможно не запускался)."
if ask_yes_no "Остановить game и login (profile l2)?" "n"; then
docker compose "${PROFILE_L2[@]}" stop game login 2>/dev/null || true
fi
if ask_yes_no "Остановить только PostgreSQL (docker compose stop postgres)?" "n"; then
docker compose stop postgres 2>/dev/null || warn "PostgreSQL уже остановлен или не создавался."
if ask_yes_no "Остановить PostgreSQL?" "n"; then
docker compose stop postgres 2>/dev/null || true
fi
if ask_yes_no "Полная остановка проекта: docker compose down (все сервисы, сеть; тома БД не удаляются)?" "n"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" down
info "Контейнеры остановлены. Данные БД в томе postgres_data сохранены."
if ask_yes_no "docker compose down (все сервисы, том БД сохраняется)?" "n"; then
docker compose "${PROFILE_L2[@]}" down
docker compose down
fi
if ask_yes_no "Удалить том с данными PostgreSQL (docker compose down -v)? ОПАСНО: потеря БД." "n"; then
warn "Будет выполнено: docker compose --profile placeholder down -v"
if ask_yes_no "Точно удалить тома?" "n"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" down -v
info "Тома удалены."
else
info "Отмена удаления томов."
if ask_yes_no "Удалить том БД (down -v)? ОПАСНО." "n"; then
if ask_yes_no "Точно удалить?" "n"; then
docker compose "${PROFILE_L2[@]}" down -v
docker compose down -v
fi
fi
# --- Шаг 3: запуск ---
step_header "Шаг 3 — Запуск"
if ask_yes_no "Запустить / обновить PostgreSQL (up -d postgres)?" "n"; then
if ask_yes_no "Запустить PostgreSQL?" "n"; then
docker compose up -d postgres
info "Ожидание pg_isready..."
EV_USER="$(read_env_val POSTGRES_USER)"
EV_DB="$(read_env_val POSTGRES_DB)"
for _ in $(seq 1 60); do
if docker compose exec -T postgres pg_isready -U "$EV_USER" -d "$EV_DB" >/dev/null 2>&1; then
break
fi
docker compose exec -T postgres pg_isready -U "$EV_USER" -d "$EV_DB" >/dev/null 2>&1 && break
sleep 1
done
fi
if ask_yes_no "Запустить l2-server (placeholder, нужен здоровый PostgreSQL)?" "n"; then
if ! postgres_running; then
warn "PostgreSQL не запущен. Сначала поднимите postgres."
if ask_yes_no "Запустить login + game (profile l2)?" "n"; then
if postgres_running; then
docker compose "${PROFILE_L2[@]}" up -d login game
else
docker compose "${PROFILE_PLACEHOLDER[@]}" up -d l2-server
warn "Сначала поднимите postgres."
fi
fi
# --- Шаг 4: перезапуск ---
step_header "Шаг 4 — Перезапуск"
if ask_yes_no "Перезапустить PostgreSQL (restart postgres)?" "n"; then
if ask_yes_no "Перезапустить PostgreSQL?" "n"; then
if postgres_running; then
docker compose restart postgres
info "PostgreSQL перезапущен."
else
warn "PostgreSQL не в состоянии running. Выполняю up -d postgres."
docker compose up -d postgres
fi
fi
if ask_yes_no "Перезапустить l2-server (restart l2-server)?" "n"; then
if l2_running; then
docker compose "${PROFILE_PLACEHOLDER[@]}" restart l2-server
info "l2-server перезапущен."
else
warn "l2-server не запущен. Пропуск."
fi
if ask_yes_no "Перезапустить login?" "n"; then
login_running && docker compose "${PROFILE_L2[@]}" restart login || warn "login не запущен."
fi
if ask_yes_no "Перезапустить весь стек: сначала down, затем up postgres (+ опционально l2)?" "n"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" down
if ask_yes_no "Перезапустить game?" "n"; then
game_running && docker compose "${PROFILE_L2[@]}" restart game || warn "game не запущен."
fi
if ask_yes_no "Полный перезапуск: down → postgres → login → game?" "n"; then
docker compose "${PROFILE_L2[@]}" down
docker compose down
docker compose up -d postgres
EV_USER="$(read_env_val POSTGRES_USER)"
EV_DB="$(read_env_val POSTGRES_DB)"
for _ in $(seq 1 60); do
if docker compose exec -T postgres pg_isready -U "$EV_USER" -d "$EV_DB" >/dev/null 2>&1; then
break
fi
sleep 1
done
if ask_yes_no "Сразу поднять l2-server (placeholder)?" "n"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" up -d l2-server
fi
info "Стек перезапущен."
sleep 3
docker compose "${PROFILE_L2[@]}" up -d login game
fi
# --- Итог ---
step_header "Готово"
if ask_yes_no "Показать итоговый статус?" "y"; then
docker compose "${PROFILE_PLACEHOLDER[@]}" ps -a || true
if ask_yes_no "Показать статус?" "y"; then
docker compose ps -a
docker compose "${PROFILE_L2[@]}" ps -a 2>/dev/null || true
fi
info "Логи: docker compose logs -f postgres"
info "Выход из проекта без удаления томов: docker compose --profile placeholder down"
info "Логи: docker compose logs -f login game postgres"
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Применить SQL к уже существующей БД (если том postgres не пересоздавали).
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
ENV_FILE="${ROOT}/.env"
[[ -f "$ENV_FILE" ]] || { echo "Нет .env — сначала ./install.sh"; exit 1; }
read_env() { grep -m1 "^${1}=" "$ENV_FILE" | sed "s/^${1}=//"; }
U="$(read_env POSTGRES_USER)"
DB="$(read_env POSTGRES_DB)"
export PGPASSWORD="$(read_env POSTGRES_PASSWORD)"
for f in "$ROOT"/docker/initdb/0*.sql; do
echo "==> $(basename "$f")"
docker compose exec -T postgres psql -v ON_ERROR_STOP=1 -U "$U" -d "$DB" -f - <"$f"
done
echo "Готово."
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Подставить POSTGRES_* из .env в config/login и config/game (без коммита .env).
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_FILE="${ROOT}/.env"
[[ -f "$ENV_FILE" ]] || { echo "Нет .env"; exit 1; }
read_env() { grep -m1 "^${1}=" "$ENV_FILE" | sed "s/^${1}=//"; }
U="$(read_env POSTGRES_USER)"
P="$(read_env POSTGRES_PASSWORD)"
DB="$(read_env POSTGRES_DB)"
for f in "$ROOT/config/login/LoginServer.properties" "$ROOT/config/game/Server.properties"; do
[[ -f "$f" ]] || continue
sed -i "s|^Login = .*|Login = $U|" "$f"
sed -i "s|^Password = .*|Password = $P|" "$f"
sed -i "s|jdbc:postgresql://postgres:5432/[^?]*|jdbc:postgresql://postgres:5432/$DB|" "$f"
echo "Обновлён: $f"
done
View File
+1
View File
@@ -0,0 +1 @@
a1b2c3d4e5f6789012345678901234ef
View File