feat(delta): /delta command, Display tracking budget, global delta config; rewrite README for Delta
Build Delta / Build paperclip jar (push) Failing after 4m52s
Build Delta / Build paperclip jar (push) Failing after 4m52s
This commit is contained in:
@@ -1,100 +1,103 @@
|
|||||||
Paper [](https://github.com/PaperMC/Paper/actions)
|
# Delta
|
||||||
[](https://discord.gg/papermc)
|
|
||||||
[](https://github.com/sponsors/PaperMC)
|
|
||||||
[](https://opencollective.com/papermc)
|
|
||||||
===========
|
|
||||||
|
|
||||||
The most widely used, high-performance Minecraft server that aims to fix gameplay and mechanics inconsistencies.
|
Экспериментальное серверное ядро на базе [Paper](https://github.com/PaperMC/Paper) для 1.21.8.
|
||||||
|
|
||||||
|
Сделано под узкие задачи: PvP-сервер с большим количеством кастомных способностей,
|
||||||
|
тяжёлыми визуальными эффектами (Display-сущности, частицы, звуки) и ограниченным
|
||||||
|
железом. Основная цель — выжать больше производительности с 4 vCPU / 8 ГБ RAM, не
|
||||||
|
ломая совместимость плагинов.
|
||||||
|
|
||||||
**Support and Project Discussion:**
|
> **Не для публичного использования.** Ядро собирается под конкретный сервер и не
|
||||||
- [Our forums](https://forums.papermc.io/) or [Discord](https://discord.gg/papermc)
|
> имеет ни стабильности, ни гарантий безопасности. Не публикуйте его и не
|
||||||
|
> стройте на нём публичные проекты.
|
||||||
|
|
||||||
How To (Server Admins)
|
---
|
||||||
------
|
|
||||||
Paperclip is a jar file that you can download and run just like a normal jar file.
|
|
||||||
|
|
||||||
Download Paper from our [downloads page](https://papermc.io/downloads/paper).
|
## Совместимость — это приоритет
|
||||||
|
|
||||||
Run the Paperclip jar directly from your server. Just like old times
|
Delta — **не форк с поломанным API**. Плагины видят ровно то же, что и на Paper:
|
||||||
|
|
||||||
* Documentation on using Paper: [docs.papermc.io](https://docs.papermc.io)
|
| Что | Значение | Почему |
|
||||||
* For a sneak peek at upcoming features, [see here](https://github.com/PaperMC/Paper/projects)
|
|---|---|---|
|
||||||
|
| Группа артефакта | `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 | не трогаем вообще |
|
||||||
|
| Порядок тиков | стоковый | многопоток не трогает семантику |
|
||||||
|
|
||||||
How To (Plugin Developers)
|
Отличие только в отображении: `Brand-Name = Delta`, поэтому в F3 видно
|
||||||
------
|
`server: Delta`. Это **единственное** пользовательское отличие.
|
||||||
* See our API [here](paper-api)
|
|
||||||
* See upcoming, pending, and recently added API [here](https://github.com/orgs/PaperMC/projects/2/views/4)
|
|
||||||
* Paper API javadocs here: [papermc.io/javadocs](https://papermc.io/javadocs/)
|
|
||||||
#### Repository (for paper-api)
|
|
||||||
##### Maven
|
|
||||||
|
|
||||||
```xml
|
## Что добавлено
|
||||||
<repository>
|
|
||||||
<id>papermc</id>
|
### `/delta` — инспекция и тюнинг
|
||||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
```
|
||||||
</repository>
|
/delta status текущие значения конфигурации
|
||||||
|
/delta displayrange <блоки|0> дальность трекинга Display, 0 = стоковая
|
||||||
|
/delta reload перечитать конфиг
|
||||||
|
```
|
||||||
|
Периметр `delta.admin`.
|
||||||
|
|
||||||
|
### Бюджет Display-сущностей
|
||||||
|
В `ChunkMap.TrackedEntity#updatePlayer` добавлен кламп дальности трекинга для
|
||||||
|
`Display`. Display-сущности не имеют физики и коллизий, поэтому их отсечение по
|
||||||
|
дальности безопасно: клиент просто их не видит, серверное состояние остаётся
|
||||||
|
корректным. Это снимает основную нагрузку от способностей, спавнящих
|
||||||
|
десятки `BlockDisplay` с `viewRange=64`.
|
||||||
|
|
||||||
|
Отключено по умолчанию — включается в `paper-global.yml`:
|
||||||
|
```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
|
||||||
```
|
```
|
||||||
|
|
||||||
```xml
|
### Баннер при старте
|
||||||
<dependency>
|
При запуске печатается блок с версией, коммитом, веткой, списком включённых
|
||||||
<groupId>io.papermc.paper</groupId>
|
Delta-фич и предупреждением о статусе ядра.
|
||||||
<artifactId>paper-api</artifactId>
|
|
||||||
<version>1.21.8-R0.1-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
```
|
|
||||||
##### Gradle
|
|
||||||
```kotlin
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
## Конфигурация сервера
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21.8-R0.1-SNAPSHOT")
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
Готовые тюнинг-конфиги под 4 vCPU лежат в [`zernmc-config/`](zernmc-config/) —
|
||||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
трекинг сущностей, активация, хопперы, чанковая система, редстоун. Это
|
||||||
}
|
партиальные файлы: Paper мержит их с дефолтами.
|
||||||
|
|
||||||
|
## Сборка
|
||||||
|
|
||||||
|
Требуется JDK 21. Две фазы, **обязательно отдельными вызовами** — при объединении
|
||||||
|
падает с ошибкой неявной зависимости `applyResourcePatches -> processResources`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew applyPatches
|
||||||
|
./gradlew createMojmapPaperclipJar
|
||||||
```
|
```
|
||||||
|
|
||||||
How To (Compiling Jar From Source)
|
Артефакты: `paper-server/build/libs/paper-paperclip-*.jar`
|
||||||
------
|
|
||||||
To compile Paper, you need JDK 21 and an internet connection.
|
|
||||||
|
|
||||||
Clone this repo, run `./gradlew applyPatches`, then `./gradlew createMojmapBundlerJar` from your terminal. You can find the compiled jar in the `paper-server/build/libs` directory.
|
## CI
|
||||||
|
|
||||||
To get a full list of tasks, run `./gradlew tasks`.
|
Gitea Actions, воркфлоу `.gitea/workflows/build.yml`. Раннер живёт на отдельной
|
||||||
|
машине с 4 vCPU — на слабом хосте сборка невозможна.
|
||||||
|
|
||||||
How To (Pull Request)
|
Джобы выполняются в образе `delta-builder:jdk21` (JDK 21 + node + git identity).
|
||||||
------
|
Node обязателен для `actions/checkout`, git identity — для `applyFeaturePatches`,
|
||||||
See [Contributing](CONTRIBUTING.md)
|
который делает commit.
|
||||||
|
|
||||||
Old Versions (1.21.3 and below)
|
## Планируется
|
||||||
------
|
|
||||||
For branches of versions 1.8-1.21.3, please see our [archive repository](https://github.com/PaperMC/Paper-archive).
|
|
||||||
|
|
||||||
Support Us
|
- Раздельные громкость и дальность звука (сейчас это один и тот же параметр —
|
||||||
------
|
чтобы было слышно за 150 блоков, приходится делать volume=10, и в упор всё
|
||||||
First of all, thank you for considering helping out, we really appreciate that!
|
клиппит)
|
||||||
|
- `force`/`alwaysShow` в публичном API частиц (сейчас недоступны плагинам)
|
||||||
|
- Вынос симуляции «безопасных» чанков в worker-треды Moonrise — с чек-листом,
|
||||||
|
исключающим BlockEntity и плагинные блоки, чтобы не сломать совместимость
|
||||||
|
|
||||||
PaperMC has various recurring expenses, mostly related to infrastructure. Paper uses [Open Collective](https://opencollective.com/) via the [Open Source Collective fiscal host](https://opencollective.com/opensource) to manage expenses. Open Collective allows us to be extremely transparent, so you can always see how your donations are used. You can read more about financially supporting PaperMC [on our website](https://papermc.io/sponsors).
|
## Лицензия
|
||||||
|
|
||||||
You can find our collective [here](https://opencollective.com/papermc), or you can donate via GitHub Sponsors [here](https://github.com/sponsors/PaperMC), which will also go towards the collective.
|
Код ядра наследует лицензию Paper ([GPLv3](LICENSE.md)). Все изменения в
|
||||||
|
`me.sashegdev.delta` — тоже GPLv3.
|
||||||
Special Thanks To:
|
|
||||||
-------------
|
|
||||||
|
|
||||||
[](https://www.yourkit.com/)
|
|
||||||
|
|
||||||
[YourKit](https://www.yourkit.com/), makers of the outstanding java profiler, support open source projects of all kinds with their full featured [Java](https://www.yourkit.com/java/profiler) and [.NET](https://www.yourkit.com/.net/profiler) application profilers. We thank them for granting Paper an OSS license so that we can make our software the best it can be.
|
|
||||||
|
|
||||||
[<img src="https://user-images.githubusercontent.com/21148213/121807008-8ffc6700-cc52-11eb-96a7-2f6f260f8fda.png" alt="" width="150">](https://www.jetbrains.com)
|
|
||||||
|
|
||||||
[JetBrains](https://www.jetbrains.com/), creators of the IntelliJ IDEA, supports Paper with one of their [Open Source Licenses](https://www.jetbrains.com/opensource/). IntelliJ IDEA is the recommended IDE for working with Paper, and most of the Paper team uses it.
|
|
||||||
|
|
||||||
All our sponsors!
|
|
||||||
[](https://papermc.io/sponsors)
|
|
||||||
@@ -24,6 +24,9 @@ public final class PaperCommands {
|
|||||||
public static void registerCommands(final MinecraftServer server) {
|
public static void registerCommands(final MinecraftServer server) {
|
||||||
COMMANDS.put("paper", new PaperCommand("paper"));
|
COMMANDS.put("paper", new PaperCommand("paper"));
|
||||||
COMMANDS.put("mspt", new MSPTCommand("mspt"));
|
COMMANDS.put("mspt", new MSPTCommand("mspt"));
|
||||||
|
// Delta start - /delta core command
|
||||||
|
COMMANDS.put("delta", new me.sashegdev.delta.DeltaCommand("delta"));
|
||||||
|
// Delta end
|
||||||
|
|
||||||
COMMANDS.forEach((s, command) -> {
|
COMMANDS.forEach((s, command) -> {
|
||||||
server.server.getCommandMap().register(s, "Paper", command);
|
server.server.getCommandMap().register(s, "Paper", command);
|
||||||
|
|||||||
@@ -220,6 +220,10 @@ public class GlobalConfiguration extends ConfigurationPart {
|
|||||||
@SuppressWarnings("unused") // used in postProcess
|
@SuppressWarnings("unused") // used in postProcess
|
||||||
public ChunkSystem chunkSystem;
|
public ChunkSystem chunkSystem;
|
||||||
|
|
||||||
|
// Delta start - custom core config (paper-global.yml section "delta")
|
||||||
|
public me.sashegdev.delta.DeltaConfig delta;
|
||||||
|
// Delta end
|
||||||
|
|
||||||
public class ChunkSystem extends ConfigurationPart {
|
public class ChunkSystem extends ConfigurationPart {
|
||||||
|
|
||||||
public int ioThreads = -1;
|
public int ioThreads = -1;
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package me.sashegdev.delta;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /delta — инспекция и настройка патчей Delta.
|
||||||
|
*/
|
||||||
|
public class DeltaCommand extends Command {
|
||||||
|
|
||||||
|
private static final List<String> SUBS = Arrays.asList("status", "displayrange", "reload", "help");
|
||||||
|
|
||||||
|
public DeltaCommand(String name) {
|
||||||
|
super(name);
|
||||||
|
setDescription("Delta core inspection and tuning");
|
||||||
|
setPermission("delta.admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("delta.admin")) {
|
||||||
|
sender.sendMessage(Component.text("No permission", NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String sub = args.length == 0 ? "status" : args[0].toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
|
switch (sub) {
|
||||||
|
case "status" -> {
|
||||||
|
var cfg = io.papermc.paper.configuration.GlobalConfiguration.get().delta;
|
||||||
|
sender.sendMessage(header());
|
||||||
|
sender.sendMessage(line("display range ", cfg.displayTrackingRangeEnabled
|
||||||
|
? cfg.displayTrackingRange + " blocks" : "stock (disabled)"));
|
||||||
|
sender.sendMessage(line("particle budget ", cfg.particleBudgetPerPlayerPerTick <= 0
|
||||||
|
? "off" : cfg.particleBudgetPerPlayerPerTick + " pkts/player/tick"));
|
||||||
|
sender.sendMessage(line("sound budget ", cfg.soundBudgetPerPlayerPerSecond <= 0
|
||||||
|
? "off" : cfg.soundBudgetPerPlayerPerSecond + " pkts/player/sec"));
|
||||||
|
sender.sendMessage(line("extended distance ", cfg.extendedParticleDistanceEnabled
|
||||||
|
? cfg.extendedParticleDistance + " blocks" : "off"));
|
||||||
|
sender.sendMessage(line("decoupled sound ", String.valueOf(cfg.decoupledSoundRangeEnabled)));
|
||||||
|
if (sender instanceof Player p) {
|
||||||
|
sender.sendMessage(line("your view distance", String.valueOf(p.getViewDistance())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "displayrange" -> {
|
||||||
|
var cfg = io.papermc.paper.configuration.GlobalConfiguration.get().delta;
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(line("display range ", cfg.displayTrackingRangeEnabled
|
||||||
|
? cfg.displayTrackingRange + " blocks" : "stock (disabled)"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int value;
|
||||||
|
try {
|
||||||
|
value = Integer.parseInt(args[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage(Component.text("Not a number: " + args[1], NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (value <= 0) {
|
||||||
|
cfg.displayTrackingRangeEnabled = false;
|
||||||
|
sender.sendMessage(Component.text("Display range override disabled (stock Paper)", NamedTextColor.YELLOW));
|
||||||
|
} else {
|
||||||
|
cfg.displayTrackingRangeEnabled = true;
|
||||||
|
cfg.displayTrackingRange = value;
|
||||||
|
sender.sendMessage(Component.text("Display tracking range set to " + value + " blocks", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
io.papermc.paper.configuration.GlobalConfiguration.save();
|
||||||
|
}
|
||||||
|
case "reload" -> {
|
||||||
|
io.papermc.paper.configuration.GlobalConfiguration.get().load();
|
||||||
|
sender.sendMessage(Component.text("Delta config reloaded", NamedTextColor.GREEN));
|
||||||
|
sender.sendMessage(line("display range ", DeltaTracking.describe()));
|
||||||
|
}
|
||||||
|
case "help" -> sender.sendMessage(Component.text(
|
||||||
|
"/delta status | /delta displayrange <blocks|0> | /delta reload", NamedTextColor.YELLOW));
|
||||||
|
default -> sender.sendMessage(Component.text("Unknown subcommand: " + sub, NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("delta.admin")) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
if (args.length == 1) {
|
||||||
|
String low = args[0].toLowerCase(Locale.ROOT);
|
||||||
|
List<String> out = new ArrayList<>();
|
||||||
|
for (String s : SUBS) {
|
||||||
|
if (s.startsWith(low)) {
|
||||||
|
out.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
if (args.length == 2 && args[0].equalsIgnoreCase("displayrange")) {
|
||||||
|
return List.of("0", "48", "64", "96");
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component header() {
|
||||||
|
return Component.text("---- Delta ----", NamedTextColor.DARK_PURPLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component line(String key, String value) {
|
||||||
|
return Component.text(key, NamedTextColor.GRAY).append(Component.text(value, NamedTextColor.WHITE));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package me.sashegdev.delta;
|
||||||
|
|
||||||
|
import io.papermc.paper.configuration.ConfigurationPart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конфигурация Delta. Живёт в {@code paper-global.yml} в секции {@code delta}.
|
||||||
|
* Все поля выключены по умолчанию, кроме Display-трекинга — он включается
|
||||||
|
* только явно, чтобы стоковое поведение Paper осталось эталоном.
|
||||||
|
*/
|
||||||
|
public class Delta extends ConfigurationPart {
|
||||||
|
|
||||||
|
/** Резать дальность трекинга Display-сущностей (вместо стоковых 128). */
|
||||||
|
public boolean displayTrackingRangeEnabled = false;
|
||||||
|
public int displayTrackingRange = 64;
|
||||||
|
|
||||||
|
/** Потолок пакетов частиц на игрока за тик. 0 = выключено. */
|
||||||
|
public int particleBudgetPerPlayerPerTick = 0;
|
||||||
|
|
||||||
|
/** Потолок пакетов звука на игрока за секунду. 0 = выключено. */
|
||||||
|
public int soundBudgetPerPlayerPerSecond = 0;
|
||||||
|
|
||||||
|
/** Разрешить частицам/звукам уходить дальше стандартных 32/16 блоков. */
|
||||||
|
public boolean extendedParticleDistanceEnabled = false;
|
||||||
|
public double extendedParticleDistance = 128.0D;
|
||||||
|
|
||||||
|
/** Раздельные громкость и дальность звука (для DeltaSound). */
|
||||||
|
public boolean decoupledSoundRangeEnabled = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package me.sashegdev.delta;
|
||||||
|
|
||||||
|
import io.papermc.paper.configuration.GlobalConfiguration;
|
||||||
|
import net.minecraft.world.entity.Display;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Бюджет и дальность трекинга сущностей.
|
||||||
|
*
|
||||||
|
* <p>Вызывается из {@code ChunkMap.TrackedEntity#updatePlayer} — это единая
|
||||||
|
* точка, где решается, полетит ли сущность клиенту. Display-сущности
|
||||||
|
* (BlockDisplay/TextDisplay/ItemDisplay) не имеют коллизий и физики, поэтому
|
||||||
|
* их можно безопасно резать по дальности: клиент их просто не увидит, но
|
||||||
|
* серверное состояние останется корректным.
|
||||||
|
*/
|
||||||
|
public final class DeltaTracking {
|
||||||
|
|
||||||
|
private DeltaTracking() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return эффективную дальность трекинга с учётом Delta-конфига
|
||||||
|
*/
|
||||||
|
public static double adjustRange(final Entity entity, final double range) {
|
||||||
|
if (!(entity instanceof Display)) {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
final DeltaConfig cfg = delta();
|
||||||
|
if (cfg == null || !cfg.displayTrackingRangeEnabled) {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
final int configured = cfg.displayTrackingRange;
|
||||||
|
return configured <= 0 ? range : Math.min(range, configured);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DeltaConfig delta() {
|
||||||
|
try {
|
||||||
|
return GlobalConfiguration.get().delta;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// конфиг ещё не инициализирован (например, очень ранний вызов)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String describe() {
|
||||||
|
final DeltaConfig cfg = delta();
|
||||||
|
if (cfg == null) {
|
||||||
|
return "config not loaded";
|
||||||
|
}
|
||||||
|
if (!cfg.displayTrackingRangeEnabled) {
|
||||||
|
return "display tracking: stock (disabled)";
|
||||||
|
}
|
||||||
|
return "display tracking: " + cfg.displayTrackingRange + " blocks";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user