Slomix / ParkourBeat

4 stars 5 forks source link

Реализация более тонкого контроля сервера за воспроизведением музыки клиента (продолжение #26) #40

Open DrupalDoesNotExists opened 8 months ago

DrupalDoesNotExists commented 8 months ago

Пара идей от witwar:

  1. Отказаться от механики спринта, запретить всем игрокам спринт посредством уменьшения насыщения (голод). Но при это увеличить скорость передвижения модификатором/эффектом/маяком
  2. Разделить цельный трек на несколько кусков примерно одного размера и отсылать их в зависимости от процента прохождения карты игроком. Вместе с этим необходимо отсылать пакет остановки предыдущего звука. К каждому куску можно добавить ещё 1-2-3 секунды на случай сильного рассинхрона или пинга

По поводу 2-ого пункта. В связи с тем, что остановка предыдущего звука должна быть обработана раньше, но в тот же тик, что и начало нового звука, с чётким соблюдением порядка - придётся использовать бандлы. К сожалению они доступны с 1.20, поэтому на версиях раньше такой механизм может вызвать проблемы.

Сами бандлы так же добавляют оверхед в виде 1 пакета (Bundle Delimiter). Соответственно, карман на случай пинга в конце основного сегмента трека, который мы отправляем, должен быть в 3 раза дольше, чем максимальный пинг, который мы планируем покрыть:

Если мы хотим покрыть игроков с пингом ≤ 250мс, то надо оставлять карман в 750мс (1 секунду).

По поводу поддержки бандлов на версиях < 1.20. Теоретически можно реализовать бандлы на версиях ниже 1.20 манипуляциями с netty и тем, как он отправляет пакеты, а ещё с тем как клиент их читает. AFAIK клиент читает входящие данные при десериализации в виде потока. Теоретически можно попробовать упаковать несколько протоколовских пакетов в 1 реальный TCP пакет, чтобы клиент получил все нужные действия разом и обработал их соответственно в один тик (если говорить по-научному, то это своеобразная версия алгоритма Нейгла). Это требует конкретных исследований и экспериментов, да и возможно тянет на отдельную библиотеку широкого спектра для Spigot/PaperMC плагинов, но может быть полезно в нашем случае.

P.S.: в таком случае оверхед по размеру кармана снижается до 2x максимального пинга, ведь нет необходимости в третьем пакете Bundle Delimiter'е.

Конкретно в netty за включение и отключение алгоритма Нейгла в общем отвечает TCP_NODELAY опция. Но трогать её лучше не стоит, ведь нам нужно врубить её на один канал на несколько пакетов. По идее, её существование просто гарантирует, что такой мув вообще будет восприниматься адекватно и клиент не крашнется и не улетит на небеса от такой оптимизации.

Мы провели тестирование с целью выявить поддержку алгоритма Нейгла у клиента. Для этого мы брали Netty Channel подключения игрока при входе и изменяли настройку TCP_NODELAY на false, что должно было обеспечивать работу алгоритма Нейгла. Клиент успешно воспринимал пакеты в таком режиме.

Тестирование проводилось на платформе со следующими параметрами: Linux 5.4.0-144-generic #161-Ubuntu SMP Fri Feb 3 14:49:04 UTC 2023 x86_64 x86_64 GNU/Linux, версии майнкрафта 1.20.4. Сервер на основе PaperMC.

Возможно это предпосылки к бэкпортам бандлов на версии ниже 1.20!

Originally posted by @DrupalDoesNotExists in https://github.com/Slomix/ParkourBeat/issues/26#issuecomment-1981558224

DrupalDoesNotExists commented 7 months ago

Работа самого концепта с карманами и пингом проверена и концепт является полностью рабочим - музыка не прерывается даже при пинге >250мс при кармане в 1сек.

По поводу бандлов на версиях ниже 1.20 я провёл дополнительные исследования и для реализации написал библиотеку. Больше информации в README указанного репозитория.

Точно известно, что с версии 1.7 по новейшие в коде Minecraft есть ChannelHandler'ы, отвечающие за разделение пакетов по полю длины, поэтому поддержка нейглинга подтверждена у всех версий.