feat(delta): config persistence via Configurations.saveGlobalSection + decoupled sound range API
Build Delta / Build paperclip jar (push) Failing after 5m52s
Build Delta / Build paperclip jar (push) Failing after 5m52s
This commit is contained in:
@@ -3616,6 +3616,28 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
|||||||
*/
|
*/
|
||||||
void playSound(@NotNull Entity entity, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, long seed);
|
void playSound(@NotNull Entity entity, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, long seed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delta: plays a sound with an explicit audible range, decoupled from volume.
|
||||||
|
* <p>
|
||||||
|
* In vanilla the audible distance is derived from volume (16 blocks per volume unit),
|
||||||
|
* so a sound that must be heard 150 blocks away requires volume ~10, which then clips
|
||||||
|
* badly for players standing next to the source. This overload lets you pick gain and
|
||||||
|
* distance independently.
|
||||||
|
* <p>
|
||||||
|
* Requires the Delta core with {@code delta.decoupled-sound-range-enabled: true};
|
||||||
|
* on any other server it silently falls back to vanilla behaviour.
|
||||||
|
*
|
||||||
|
* @param location the location to play the sound at
|
||||||
|
* @param sound the sound to play
|
||||||
|
* @param category the category of the sound
|
||||||
|
* @param volume the loudness at the source
|
||||||
|
* @param pitch the pitch of the sound
|
||||||
|
* @param range the audible radius in blocks, independent of volume
|
||||||
|
*/
|
||||||
|
default void playSound(@NotNull Location location, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, float range) {
|
||||||
|
playSound(location, sound, category, volume, pitch); // fallback: range == f(volume)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a Sound at the location of the provided entity in the World. For sounds
|
* Play a Sound at the location of the provided entity in the World. For sounds
|
||||||
* with multiple variations passing the same seed will always play the same
|
* with multiple variations passing the same seed will always play the same
|
||||||
|
|||||||
@@ -139,6 +139,23 @@ public abstract class Configurations<G, W> {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delta start - persist a single global config section
|
||||||
|
// Paper exposes no way to write paper-global.yml back after boot: reloadConfigs()
|
||||||
|
// re-reads from disk and would clobber any in-memory change. This writes just the
|
||||||
|
// requested section and leaves every other node exactly as it was parsed, so it can
|
||||||
|
// never damage unrelated settings.
|
||||||
|
public void saveGlobalSection(final RegistryAccess registryAccess, final String section, final Object value) throws ConfigurateException {
|
||||||
|
final Path configFile = this.globalFolder.resolve(this.globalConfigFileName);
|
||||||
|
final YamlConfigurationLoader loader = this.createGlobalLoaderBuilder(registryAccess)
|
||||||
|
.defaultOptions(this.applyObjectMapperFactory(this.createGlobalObjectMapperFactoryBuilder().build()))
|
||||||
|
.path(configFile)
|
||||||
|
.build();
|
||||||
|
final ConfigurationNode node = loader.load();
|
||||||
|
node.node(section).set(value);
|
||||||
|
trySaveFileNode(loader, node, configFile.toString());
|
||||||
|
}
|
||||||
|
// Delta end
|
||||||
|
|
||||||
protected void verifyGlobalConfigVersion(final ConfigurationNode globalNode) {
|
protected void verifyGlobalConfigVersion(final ConfigurationNode globalNode) {
|
||||||
final ConfigurationNode version = globalNode.node(Configuration.VERSION_FIELD);
|
final ConfigurationNode version = globalNode.node(Configuration.VERSION_FIELD);
|
||||||
if (version.virtual()) {
|
if (version.virtual()) {
|
||||||
|
|||||||
@@ -73,17 +73,14 @@ public class DeltaCommand extends Command {
|
|||||||
cfg.displayTrackingRange = value;
|
cfg.displayTrackingRange = value;
|
||||||
sender.sendMessage(Component.text("Display tracking range set to " + value + " blocks", NamedTextColor.GREEN));
|
sender.sendMessage(Component.text("Display tracking range set to " + value + " blocks", NamedTextColor.GREEN));
|
||||||
}
|
}
|
||||||
// Paper не даёт публичного API для записи paper-global.yml, поэтому
|
// Paper не даёт публичного API для записи paper-global.yml — Delta добавляет
|
||||||
// это живая правка только в памяти: после рестарта вернётся значение
|
// saveGlobalSection(), который пишет только секцию delta и не трогает остальное.
|
||||||
// из конфига. Постоянно — правкой paper-global.yml -> delta.
|
persist(sender, "display range");
|
||||||
sender.sendMessage(Component.text(
|
|
||||||
"Runtime-only. For a permanent change edit paper-global.yml -> delta.",
|
|
||||||
NamedTextColor.GRAY));
|
|
||||||
}
|
}
|
||||||
case "clear" -> {
|
case "clear" -> {
|
||||||
var cfg = io.papermc.paper.configuration.GlobalConfiguration.get().delta;
|
var cfg = io.papermc.paper.configuration.GlobalConfiguration.get().delta;
|
||||||
cfg.displayTrackingRangeEnabled = false;
|
cfg.displayTrackingRangeEnabled = false;
|
||||||
sender.sendMessage(Component.text("Runtime override cleared, back to config values", NamedTextColor.YELLOW));
|
persist(sender, "display range");
|
||||||
sender.sendMessage(line("display range ", DeltaTracking.describe()));
|
sender.sendMessage(line("display range ", DeltaTracking.describe()));
|
||||||
}
|
}
|
||||||
case "help" -> sender.sendMessage(Component.text(
|
case "help" -> sender.sendMessage(Component.text(
|
||||||
@@ -114,6 +111,25 @@ public class DeltaCommand extends Command {
|
|||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Пишет секцию {@code delta} обратно в paper-global.yml.
|
||||||
|
* Записывается только наша секция — остальные узлы файла остаются как были распарсены,
|
||||||
|
* поэтому сломать чужие настройки этим невозможно.
|
||||||
|
*/
|
||||||
|
private void persist(final CommandSender sender, final String what) {
|
||||||
|
final var server = Bukkit.getServer();
|
||||||
|
try {
|
||||||
|
server.paperConfigurations().saveGlobalSection(
|
||||||
|
server.registryAccess(), "delta",
|
||||||
|
io.papermc.paper.configuration.GlobalConfiguration.get().delta);
|
||||||
|
sender.sendMessage(Component.text("Saved to paper-global.yml -> delta (" + what + ")", NamedTextColor.DARK_GREEN));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
sender.sendMessage(Component.text(
|
||||||
|
"Applied at runtime, but failed to persist: " + t.getMessage(),
|
||||||
|
NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Component header() {
|
private Component header() {
|
||||||
return Component.text("---- Delta ----", NamedTextColor.DARK_PURPLE);
|
return Component.text("---- Delta ----", NamedTextColor.DARK_PURPLE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1889,6 +1889,37 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
|||||||
this.playSound(loc, sound, category, volume, pitch, this.getHandle().random.nextLong());
|
this.playSound(loc, sound, category, volume, pitch, this.getHandle().random.nextLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delta start - decoupled sound range
|
||||||
|
// Vanilla derives audible distance from volume (SoundEvent#getRange = 16 * volume), so the
|
||||||
|
// only way to make a boss ability audible at 150 blocks is volume=10, which then clips
|
||||||
|
// badly for anyone standing next to the source. This sends the same packet with an
|
||||||
|
// explicit radius, keeping gain and distance independent.
|
||||||
|
@Override
|
||||||
|
public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, float range) {
|
||||||
|
org.spigotmc.AsyncCatcher.catchOp("play sound (decoupled range)"); // Paper
|
||||||
|
if (loc == null || sound == null || category == null) return;
|
||||||
|
if (!io.papermc.paper.configuration.GlobalConfiguration.get().delta.decoupledSoundRangeEnabled) {
|
||||||
|
this.playSound(loc, sound, category, volume, pitch, this.getHandle().random.nextLong()); // feature off: stock behaviour
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final double x = loc.getX();
|
||||||
|
final double y = loc.getY();
|
||||||
|
final double z = loc.getZ();
|
||||||
|
|
||||||
|
final net.minecraft.network.protocol.game.ClientboundSoundPacket packet = new net.minecraft.network.protocol.game.ClientboundSoundPacket(
|
||||||
|
CraftSound.bukkitToMinecraft(sound),
|
||||||
|
SoundSource.valueOf(category.name()),
|
||||||
|
x, y, z,
|
||||||
|
volume, pitch, this.getHandle().random.nextLong()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.getServer().getHandle().getPlayerList().broadcast(
|
||||||
|
null, x, y, z, range, this.getHandle().dimension(), packet
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Delta end
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) {
|
public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) {
|
||||||
org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper
|
org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper
|
||||||
|
|||||||
Reference in New Issue
Block a user