Files
SashegDev 5186c9b0e2
Build Delta / Build paperclip jar (push) Successful in 8m2s
docs: update README for the audio, display and persistence work
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.
2026-09-30 12:53:09 +00:00

175 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Delta
Экспериментальное серверное ядро на базе [Paper](https://github.com/PaperMC/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`.
Отключено по умолчанию:
```yaml
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
разделывает эти параметры:
```java
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/`](zernmc-config/) —
трекинг сущностей, активация, хопперы, чанковая система, редстоун. Это
партиальные файлы: Paper мержит их с дефолтами.
## Сборка
Требуется JDK 21. Две фазы, **обязательно отдельными вызовами** — при объединении
падает с ошибкой неявной зависимости `applyResourcePatches -> processResources`:
```bash
./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](LICENSE.md)). Все изменения в
`me.sashegdev.delta` — тоже GPLv3.