The README still described decoupled sound range as planned and had no `/delta displaylead`, no mention of the config being writable, and a command list containing a `/delta reload` that does not exist. Also corrects two claims that no longer hold: - the Display tracking clamp is in org.spigotmc.TrackingRange, not ChunkMap.TrackedEntity. That was a deliberate choice: TrackingRange is git-tracked Paper source, so the decompiled Minecraft tree stays untouched. - the new Bukkit methods are default methods, so plugins referencing them keep working on stock Paper instead of failing with NoSuchMethodError.
Delta
Экспериментальное серверное ядро на базе Paper для 1.21.8.
Сделано под узкие задачи: PvP-сервер с большим количеством кастомных способностей, тяжёлыми визуальными эффектами (Display-сущности, частицы, звуки) и ограниченным железом. Основная цель — выжать больше производительности с 4 vCPU / 8 ГБ RAM, не ломая совместимость плагинов.
Не для публичного использования. Ядро собирается под конкретный сервер и не имеет ни стабильности, ни гарантий безопасности. Не публикуйте его и не стройте на нём публичные проекты.
Совместимость — это приоритет
Delta — не форк с поломанным API. Плагины видят ровно то же, что и на Paper:
| Что | Значение | Почему |
|---|---|---|
| Группа артефакта | io.papermc.paper |
Versioning читает pom.properties по пути группы — смена ломает Bukkit.getBukkitVersion() |
| Версия | 1.21.8-R0.1-SNAPSHOT |
плагины парсят эту строку под API-фичи |
Brand-Id |
papermc:paper |
по нему работает ServerBuildInfo#isBrandCompatible |
| Пакеты | io.papermc.paper.*, net.minecraft.*, Bukkit API |
не трогаем вообще |
| Порядок тиков | стоковый | многопоток не трогает семантику |
Отличие только в отображении: Brand-Name = Delta, поэтому в F3 видно
server: Delta. Это единственное пользовательское отличие.
Все новые классы лежат в me.sashegdev.delta. Методы Bukkit API, которых
Paper не хватает, добавлены как default-методы — так ничего не ломается
бинарно, и плагин, который на них ссылается, продолжает работать на стоковом
Paper через fallback.
Что добавлено
/delta — инспекция и тюнинг
/delta status текущие значения конфигурации
/delta displayrange <блоки|0> дальность трекинга Display, 0 = стоковая
/delta displaylead <тики|0> предсказание позиции Display, 0 = стоковое
/delta clear сбросить Display-настройки к стоку
/delta help
Периметр delta.admin. Всё, что меняется через /delta, пишется в
paper-global.yml и переживает рестарт. Paper не даёт публичного API для
записи глобального конфига, поэтому добавлен saveGlobalSection(): он пишет
только секцию delta и не трогает остальные узлы файла, так что сломать чужие
настройки невозможно.
Бюджет Display-сущностей
Кламп дальности трекинга для Display живёт в
org.spigotmc.TrackingRange#getEntityTrackingRange — это git-отслеживаемый
исходник Paper, поэтому декомпилированный код Minecraft патчить не пришлось.
Display-сущности не имеют физики и коллизий, поэтому их отсечение по дальности
безопасно: клиент просто их не видит, серверное состояние остаётся корректным.
Это снимает основную нагрузку от способностей, спавнящих десятки BlockDisplay
с viewRange=64.
Отключено по умолчанию:
delta:
display-tracking-range-enabled: false
display-tracking-range: 64
particle-budget-per-player-per-tick: 0
sound-budget-per-player-per-second: 0
extended-particle-distance-enabled: false
extended-particle-distance: 128.0
decoupled-sound-range-enabled: false
display:
predictive-lead-ticks: 3
sound:
propagation-blocks-per-tick: 10.0
decay-exponent: 4.0
client-compensation: false
min-audible-gain: 0.004
Звук: раздельные громкость и дальность
В ванилле слышимая дальность выводится из громкости
(SoundEvent#getRange = 16 * volume). Единственный способ сделать звук
слышимым за 150 блоков — volume=10, и тогда всё клиппит в упор. Delta
разделывает эти параметры:
world.playSound(loc, sound, category, volume, pitch, range);
world.playSoundAttenuated(loc, sound, category, volume, pitch, range);
playSoundAttenuated отправляет ровно один пакет на игрока, отложенный до
тика прихода волны. Кадрового обновления громкости нет вообще — иначе при
десятке источников это N пакетов × M игроков каждый тик, то есть ровно тот
трафик, который здесь и убирается.
Кривая нормализованная: gain = volume * (1 - d/range)^exponent. Ноль ровно на
range, поэтому параметр дистанции осмыслен. Физический 1/r не годится: с
порогом слышимости он срезал бы всё дальше ~1000 блоков и range просто не
влиял бы на результат. Скорость волны — 10 блоков/тик, то есть 100 блоков за
0.5 с.
Плавность быстрых визуалов
DeltaDisplay держит политику предсказывающей телепортации. Display двигается
пакетами позиции, и клиент интерполирует их у себя — на реальном пинге визуал
отстаёт и дёргается. Лечится не частыми пакетами (это ровно тот трафик, который
мы убираем), а сдвигом старта: визуал рождается сразу на N тиков вперёд по своей
же траектории, и teleport_duration = N говорит клиенту растянуть телепорт на
эти же N тиков. Клиент никогда не отстаёт, пакетов столько же.
Диапазон 0–10 тиков. teleport_duration — уже стоковый Bukkit API, поэтому
Delta не добавляет плагинам новых методов: политика централизована, сдвиг
позиции делает сам плагин по траектории каждого визуала.
Баннер при старте
При запуске печатается блок с версией, коммитом, веткой, списком Delta-фич и
предупреждением о статусе ядра. Баннер выводится из статического инициализатора
PaperBootstrap до парсинга paper-global.yml, поэтому строки описывают
механизм, а фактические значения показывает /delta status — иначе баннер
печатал бы дефолты как будто это текущая конфигурация.
Конфигурация сервера
Готовые тюнинг-конфиги под 4 vCPU лежат в zernmc-config/ —
трекинг сущностей, активация, хопперы, чанковая система, редстоун. Это
партиальные файлы: Paper мержит их с дефолтами.
Сборка
Требуется JDK 21. Две фазы, обязательно отдельными вызовами — при объединении
падает с ошибкой неявной зависимости applyResourcePatches -> processResources:
./gradlew applyPatches
./gradlew createMojmapPaperclipJar
Артефакт: paper-server/build/libs/paper-paperclip-1.21.8-R0.1-SNAPSHOT-mojmap.jar
Имя delta в fill { project("delta") } влияет только на публикуемые в Maven
артефакты, локальный jar всегда остаётся paper-*.
CI
Gitea Actions, воркфлоу .gitea/workflows/build.yml. Раннер живёт на отдельной
машине с 4 vCPU — на слабом хосте сборка невозможна.
Джобы выполняются в образе delta-builder:jdk21 (JDK 21 + node + git identity).
Node обязателен для actions/checkout, git identity — для applyFeaturePatches,
который делает commit.
Воркфлоу делает обе фазы отдельными шагами: объединённый createMojmapPaperclipJar
падает на неявной зависимости.
Планируется
force/alwaysShowв публичном API частиц (сейчас недоступны плагинам)- Вынос симуляции «безопасных» чанков в worker-треды Moonrise — с чек-листом, исключающим BlockEntity и плагинные блоки, чтобы не сломать совместимость
- Калибровка
client-compensationдля затухающего звука: клиент сам гасит позиционный звук, поэтому без компенсации итог тише расчётного. Формула подгоняется по замеру, поэтому вынесена под отдельный тумблер
Лицензия
Код ядра наследует лицензию Paper (GPLv3). Все изменения в
me.sashegdev.delta — тоже GPLv3.