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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* with multiple variations passing the same seed will always play the same
|
||||
|
||||
@@ -139,6 +139,23 @@ public abstract class Configurations<G, W> {
|
||||
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) {
|
||||
final ConfigurationNode version = globalNode.node(Configuration.VERSION_FIELD);
|
||||
if (version.virtual()) {
|
||||
|
||||
@@ -73,17 +73,14 @@ public class DeltaCommand extends Command {
|
||||
cfg.displayTrackingRange = value;
|
||||
sender.sendMessage(Component.text("Display tracking range set to " + value + " blocks", NamedTextColor.GREEN));
|
||||
}
|
||||
// Paper не даёт публичного API для записи paper-global.yml, поэтому
|
||||
// это живая правка только в памяти: после рестарта вернётся значение
|
||||
// из конфига. Постоянно — правкой paper-global.yml -> delta.
|
||||
sender.sendMessage(Component.text(
|
||||
"Runtime-only. For a permanent change edit paper-global.yml -> delta.",
|
||||
NamedTextColor.GRAY));
|
||||
// Paper не даёт публичного API для записи paper-global.yml — Delta добавляет
|
||||
// saveGlobalSection(), который пишет только секцию delta и не трогает остальное.
|
||||
persist(sender, "display range");
|
||||
}
|
||||
case "clear" -> {
|
||||
var cfg = io.papermc.paper.configuration.GlobalConfiguration.get().delta;
|
||||
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()));
|
||||
}
|
||||
case "help" -> sender.sendMessage(Component.text(
|
||||
@@ -114,6 +111,25 @@ public class DeltaCommand extends Command {
|
||||
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() {
|
||||
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());
|
||||
}
|
||||
|
||||
// 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
|
||||
public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper
|
||||
|
||||
Reference in New Issue
Block a user