diff --git a/docker-compose.yml b/docker-compose.yml index 15078b4..e75a31a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,8 @@ services: environment: - TZ=Asia/Novosibirsk - DOCKER_ENABLED=true + - STATIC_ENABLED=true + - STATIC_RULES=crabs-games.art,^/minecraft/api/readme$,https://git.3crabs.space/api/v1/repos/user-penguin/gmancraft/contents/README.md?ref=main - ASSETS_LOCATION=/web - DEBUG=true - SSL_TYPE=auto diff --git a/web/minecraft/app.js b/web/minecraft/app.js new file mode 100644 index 0000000..2151373 --- /dev/null +++ b/web/minecraft/app.js @@ -0,0 +1,35 @@ +const repository = 'https://git.3crabs.space/user-penguin/gmancraft'; + +function parseLatestBuild(readme) { + // shortcut: формат строки актуальной версии README, при его смене нужен явный manifest. + const line = readme.split('\n').find(line => line.startsWith('Актуальная версия')); + const match = line?.match(/^Актуальная версия\s*—\s*\*\*(\d+\.\d+\.\d+)\*\*:\s*\[Скачать \1\]\((dist\/minecraft-lab-neoforge-spike-\1\/minecraft-lab-neoforge-spike-\1\.mrpack)\)/); + if (!match) throw new Error('Не найдена актуальная сборка'); + return { version: match[1], url: `${repository}/raw/branch/main/${match[2]}` }; +} + +async function loadLatestBuild() { + const status = document.getElementById('build-status'); + const download = document.getElementById('build-download'); + try { + const response = await fetch('/minecraft/api/readme', { + cache: 'no-store', + signal: AbortSignal.timeout(10000), + }); + if (!response.ok) throw new Error('README недоступен'); + const data = await response.json(); + if (data.encoding !== 'base64' || typeof data.content !== 'string') { + throw new Error('Неизвестный формат README'); + } + const readme = new TextDecoder().decode(Uint8Array.from(atob(data.content), char => char.charCodeAt(0))); + const build = parseLatestBuild(readme); + status.textContent = `Актуальная версия — ${build.version}`; + download.href = build.url; + download.textContent = `Скачать сборку ${build.version}`; + download.hidden = false; + } catch { + status.textContent = 'Не удалось определить актуальную версию. Открой репозиторий по ссылке внизу страницы.'; + } +} + +loadLatestBuild(); diff --git a/web/minecraft/index.html b/web/minecraft/index.html new file mode 100644 index 0000000..da740f0 --- /dev/null +++ b/web/minecraft/index.html @@ -0,0 +1,57 @@ + + + + + + + gman-world — Minecraft + + + + +
+
+ CRABS GAMES +

MINECRAFT · GMAN-WORLD

+

Твой следующий
мир начинается здесь.

+

Скачай сборку, импортируй её в Prism Launcher и заходи на сервер.

+

Адрес сервера 90.189.218.191:25565

+
+ +
+
+

01 / ИГРАТЬ

+

Minecraft-сборка

+

Проверяем актуальную версию…

+ + +

Файл .mrpack · импорт через Prism Launcher

+
    +
  1. Скачай актуальную сборку.
  2. +
  3. В Prism Launcher выбери Add Instance → Import и укажи скачанный .mrpack.
  4. +
  5. Дождись загрузки модов и запусти Minecraft.
  6. +
+
+ +
+

02 / ПЕРЕЙТИ НА НОВУЮ СБОРКУ

+

Перенос данных

+

Карта и метки Xaero, закладки рецептов JEI — из старой сборки в новую.

+ Скачать трансфер +

XaeroMapTransfer.exe · Windows 10/11 · SHA-256

+
    +
  1. Закрой Minecraft и запусти утилиту.
  2. +
  3. Укажи старую папку игры слева, новую — справа.
  4. +
  5. Нажми «Перенести данные» и дождись завершения.
  6. +
+

После пересоздания серверного мира старую карту переносить не следует. Перед переносом проверь изменения версии в репозитории.

+
+
+ + +
+ + diff --git a/web/minecraft/style.css b/web/minecraft/style.css new file mode 100644 index 0000000..dc6730f --- /dev/null +++ b/web/minecraft/style.css @@ -0,0 +1,44 @@ +:root { + color-scheme: dark; + font-family: system-ui, sans-serif; + color: #e9eee6; + background: #101510; + line-height: 1.6; +} + +* { box-sizing: border-box; } +body { margin: 0; } +main { max-width: 1120px; margin: auto; padding: 40px 28px; } +a { color: #b9e58b; text-underline-offset: 4px; } +a:hover { color: #dcffc1; } +a:focus-visible { outline: 3px solid #b9e58b; outline-offset: 5px; } +header { padding-bottom: 48px; } +.brand { font-size: 14px; font-weight: 800; letter-spacing: .16em; text-decoration: none; } +.eyebrow { color: #b9e58b; font-size: 12px; letter-spacing: .12em; font-weight: 700; } +header .eyebrow { margin-top: 64px; } +h1 { font-size: clamp(36px, 6vw, 64px); line-height: 1.1; letter-spacing: -.04em; margin: 18px 0 24px; } +h2 { font-size: 27px; line-height: 1.2; margin: 18px 0; } +.intro { max-width: 580px; color: #b7c3b3; font-size: 18px; } +.server { display: flex; flex-wrap: wrap; gap: 8px 16px; color: #b7c3b3; } +code { color: #e9eee6; font-size: 16px; overflow-wrap: anywhere; } +.downloads { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; } +section { border: 1px solid #344331; background: #192118; padding: 32px; border-radius: 12px; } +section > p { color: #b7c3b3; } +section > .eyebrow { color: #b9e58b; } +.button { display: inline-block; background: #b9e58b; color: #101510; font-weight: 750; text-decoration: none; padding: 14px 22px; margin-top: 10px; border: 1px solid #b9e58b; border-radius: 6px; } +.button:hover { color: #101510; background: #dcffc1; } +.button[hidden] { display: none; } +.secondary { background: transparent; color: #b9e58b; } +.hint { font-size: 13px; } +ol { padding-left: 22px; margin-top: 28px; } +li { padding-left: 4px; margin-bottom: 12px; } +.notice { font-size: 14px; border-left: 3px solid #b9e58b; padding-left: 14px; margin-top: 28px; } +footer { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 16px; font-size: 13px; padding-top: 32px; } +footer span { color: #b7c3b3; } + +@media (max-width: 720px) { + main { padding: 24px 18px; } + header .eyebrow { margin-top: 40px; } + .downloads { grid-template-columns: 1fr; } + section { padding: 24px; } +}