Commit Graph

8 Commits

Author SHA1 Message Date
sasheg dev 07ed4ce02d Мир: остров, дороги-дамбы, биомы; LOD ступенями; консоль сервера; баны; постобработка 2026-10-22 21:38:23 +03:00
sasheg dev d2a0a7a93b Вход без пароля, права админа и F3+B
Аутентификация переделана по схеме пользователя: лаунчер — единственный
источник токена, сервер проверяет его сам и лаунчера не спрашивает.

- rsx-auth/GameToken: токен это base64url(payload) + "." + base64url(HMAC-SHA256),
  payload {uuid, nick, aud, exp, jti, typ}, typ = session или reload.
- Сессия живёт час, reload-токен полтора часа и только внутри игры. Пакет
  SessionReload продлевает сессию и выдаёт новый reload-токен.
- Сервер проверяет подпись, аудиенс, срок и совпадение uuid. HTTP-запрос к
  лаунчеру из сервера убран.
- Клиент: окно пароля убрано совсем, ник берётся из токена, клиент сам
  продлевает сессию за 5 минут до конца.
- Для локальной разработки сервер с --dev-token пишет свой токен в
  world/dev-token.txt, клиент берёт токен оттуда.
- Права админа: свой список world/admins.txt, перечитывается раз в 5 секунд,
  поэтому право снимается на лету. Пакет AdminState.
- Ванильные блоки мира ломает только админ, режим игры прав не даёт.
- F3+B только для админов: без прав показываем отказ, с правом включаются и
  ванильные хитбоксы, и наш отладочный рендер. Права сняли посреди просмотра —
  гаснут сразу.
- run-game.ps1 умеет -Token.

Проверено на живом сервере: own session ok, player in, rights of Player given.
Тесты: протокол 34, сервер 88, форк собирается чисто.
2026-10-22 08:51:27 +03:00
sasheg dev 9980c1561d Игрок: хитбокс 1.45 в шифте и прыжок с места 1.5
- RsxPlayerTuning: высота при подкрадывании 1.45 (ванилла 1.65), прыжок с
  места 1.5, в движении ванильные 1.25, высота глаз в шифте 1.37.
- RsxPlayer: прыжок по наличию горизонтального ввода, глаза при подкрадывании.
- Патч в EntityPlayer.updateSize: высота при подкрадывании из нашего класса.
- Импульс прыжка считается обратным счетом по физике ваниллы.

AABB: редактор хитбоксов и их отрисовка

- Протокол: Hitbox (имя, зона, min/max, поворот), пакеты Hitboxes,
  HitboxInstances и HitboxesReload.
- Сервер: HitboxRegistry читает JSON-файл (world/hitboxes.json, можно
  указать --hitboxes), перечитывает его по запросу клиента и шлет наборы
  игрокам. Сломанный файл не стирает рабочие коробки, а объясняет причину.
- Клиент: RsxHitboxDebug рисует коробки через RenderGlobal.drawBoundingBox
  с подписями DebugRenderer, красит зоны (голова красная, тело желтое, ноги
  синие). Команды: /rsx hitboxes on|off|reload|list|show NAME.
- Новый модуль rsx-plugin-api с интерфейсом Hitboxes: плагин может
  зарегистрировать свои коробки. У сервера появился скрипт сборки.

Тесты: протокол 34, сервер 80 (было 74). Форк собирается чисто, 3279 классов.
2026-10-21 22:31:16 +03:00
sasheg dev c0db40f624 Контекст OpenGL и честный счетчик кадров
Пункт ноль плана: клиент теперь просит контекст 3.3 в режиме
совместимости, а не тот, что выпадал по умолчанию.

Зачем: дальний вид будет писаться шейдером GLSL 330, и контекст должен
гарантированно быть не ниже 3.3. В профиле совместимости работают и
шейдеры игры (#version 120, их 34 штуки), и наши 330-е. LWJGL 2.9.4 выше
3.3 контекст не заказывает - ограничение в его конструкторе, а не в
драйвере. Драйвер при этом дает 4.6, и расширение GL_EXT_gpu_shader4,
которое просит FXAA-шейдер игры, в этом контексте на месте.

Замер кадров теперь пишется в лог каждую секунду: средний, медиана,
1% и 0.1% low. Одного среднего мало: клиент, который идет со 60
кадрами и дважды в секунду проваливается в 10, в среднем остается 60 и
ощущается как slideshow. Медленные кадры - это то, что чувствует
игрок, поэтому окно держит все времена кадров и говорит про хвост.

Среднее и процентили видны и в HUD, так что их не надо вылавливать из
скриншотов.

Замер: 307 fps | med 2.9 ms | 1% 6.0 ms | 0.1% 18.1 ms.
2026-10-20 21:21:19 +03:00
sasheg dev 450bdecc34 Клиент говорит с сервером по нашему протоколу
Раньше клиент умел только показывать меню. Теперь он заходит на сервер,
получает наш мир и рисует его.

Как это устроено:

- Наш сетевой слой (net/rustnotmc/client/net) читает наш протокол и
  переводит его пакеты в пакеты игры. Игра остаётся игрой: у неё есть
  мир, игрок, сущности и рендер, и все они работают. Не переписывать их
  ради того, чтобы нарисовать тот же мир иначе, незачем.
- Пакеты игры, которые не имеют соответствия у нас, не отправляются, а
  наоборот: перемещение игрока и ломание блока переводятся в наши.
- Экран входа игры (GuiConnecting) заменён наш: он спрашивает у лаунчера,
  кем пришёл игрок, и подставляет это в рукопожатие.
- Соединение качается из тика игры, а не из экрана. Рукопожатие, которое
  зависит от того, что экран ещё на экране, ломается alt-tab'ом.

Вход теперь через лаунчер, а не внутри игры:

- Лаунчер уже умеет логинить игрока и отдаёт игре имя, uuid и токен
  (--username, --uuid, --accessToken). Это та же роль, что у Yggdrasil в
  ванилле, только лаунчер наш.
- Сервер спрашивает лаунчер, один из ли наш этот игрок, и заодно получает
  бан-лист. Токен используется один раз и не хранится.
- Свои аккаунты сервера, когда настроен лаунчер, закрыты: сервер с двумя
  дверями не имеет дверей. Открыть их можно флагом, но намеренно.
- Если игру запустили без лаунчера, экран всё равно спрашивает имя и
  пароль: это путь для своего сервера и для разработки.

Проверено живьём: клиент вошёл по токену лаунчера, сервер спросил
лаунчер, лаунчер сказал "свой", игрок получил мир, 210 чанков пришли и
лежат на диске, рельеф нарисован.

Что чинилось по дороге:

- Minecraft.setIngameFocus() возвращал на главное меню, когда окно
  получало фокус. Игрок как раз кликает в окно, чтобы напечатать пароль, и
  экран входа исчезал в этот самый момент.
- Ответ лаунчера разбирается, а не ищется подстрокой: {"valid": true} и
  {"valid":true} это один и тот же ответ, и сервер, который понимает
  только второй, ломает работающий лаунчер.
2026-10-19 20:10:20 +03:00
sasheg dev 966a144a64 Тик мода должен идти по игровому тику, HUD должен виден при загрузке
Тик. Моды тикали из покадрового хука, то есть получали столько тиков,
сколько кадров успевает нарисовать машина. На 200 fps это в семь раз
быстрее игры: таймер мода уезжал, а счётчик тиков модов расходился с
миром, поверх которого он нарисован. Теперь тик вызывается рядом с
runTick(), внутри того же цикла, так что у мода ровно двадцать шагов в
секунду независимо от частоты кадров.

HUD. Экран загрузки мира рисует сам, мимо хвоста кадра. Пока генерируется
ландшафт, LoadingScreenRenderer рисует в собственный framebuffer, блитит
его в окно и сам вызывает updateDisplay() — до десяти раз в секунду, из
потока, который занят генерацией. Всё, что нарисовано из покадрового хука,
стирается следующим таким выводом, поэтому оверлей пропадал на всю
загрузку и возвращался уже в мире. Добавлен отдельный вход в тот же код
рисования оверлеев, вызываемый после блита и до вывода в окно.

Заодно разделены две ошибки в RsxBootstrap: сбой тика и сбой отрисовки
больше не выключают друг друга, у каждого своя защита.

Проверено вживую: оверлей виден на экране генерации ландшафта.
2026-10-19 01:02:30 +03:00
sasheg dev b6e847e981 Инструменты для сверки с оригинальным байткодом
struct_diff сравнивает классы по составу и показывает, каких не хватает.
Но он отвечает на вопрос «того же ли набора методов», а не «тот ли код».
Оба вопроса приходится задавать: прыжки и звуки шагов были сломаны именно
кодом, который компилировался без ошибок и состоял из правильных методов.

javap_diff сравнивает инструкции построчно, вызывая javap на обоих деревьях
классификации. Наивное сравнение текста здесь бесполезно: перекомпиляция
перенумеровывает constant pool, поэтому почти каждая строка отличается
номером #123, хотя код совпадает. Инструмент убирает номера пула, сдвиги
смещений от ldc/ldc_w и форму инструкций, после чего остаётся реальная
разница.

На звуке инструмент показал, что все аудио-классы совпадают с оригиналом.
Остатки объясняются версией компилятора, а не правками: javac 8 собирает
конкатенацию строк через StringBuilder, javac 17 через invokedynamic, а
$values() у enum появился в более новых версиях.

ogg_duration читает частоту дискретизации из заголовка Vorbis и число
отсчётов из granule position последней страницы OggS. Отсюда видно, что файл
сам по себе короче или что его просто обрывают при воспроизведении, —
вопрос, который иначе приходится решать на слух.

Проверено, что все 1085 ogg совпадают с индексом по SHA-1.
2026-10-19 00:25:35 +03:00
sasheg dev bdf0ae866a Форк клиента собирается из исходников, модзагрузчик встроен в игру
Проект начинается с двух вещей: клиент, который мы действительно собрали, и
загрузчик, который является его частью, а не чем-то рядом.

Форк
- prepare-game.ps1 пересобирает клиент целиком: ванильный jar, SRG и MCP,
  SpecialSource, FernFlower, патчи, автофиксеры, javac. Идемпотентен.
- Свой код игры лежит в src-overlay, потому что src пересоздаётся при каждой
  сборке и всё написанное вручную там погибает.
- 116 патчей в patches/decompiler-fixes.txt. Каждый сверялся с оригинальным
  байткодом через javap: компиляция не ловит ошибки декомпиляции.
- struct_diff.py сравнивает исходный байткод с нашей сборкой по классам,
  интерфейсам, суперклассам, методам и полям, и отдельно проверяет, что
  пропавшие классы действительно никому не нужны.

Загрузчик
- Собирается и тестируется без игры: build.ps1 не использует classpath
  вообще, поэтому SelfTest из 128 проверок проходит без запущенного форка.
- Клиентский API не содержит ни одного игрового типа, реализацию даёт игра.
- Политика: мод меняет то, что клиент показывает, но никогда то, что истинно
  в мире. Мир, предметы, игроки и сеть принадлежат серверу.
- Capability приведены в соответствие с этой политикой: осталось шесть, и
  за каждым стоит реальная проверка. Прежние WORLD, PLAYER, NETWORK, TEXT,
  INPUT и COMMAND выдавались, но ничего не проверяли.
- Команды модов имеют область CLIENT, SERVER или BOTH. Серверные не
  выполняются на клиенте никогда.
- Свой jar загрузчика лежит в classpath игры и сборки форка.

Инструменты
- add_patch.py, чтобы каждое исправление переживало передекомпиляцию
- find_self_comparisons.py, find_remove_index_bugs.py, find_callers.py
- stage_run.py и fetch_missing.py для запуска клиента
2026-10-18 21:31:27 +03:00