package me.sashegdev.blackknife; import org.bukkit.Color; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.World; /** * Батчинг частиц. * *
Цена в плагине измеряется не в миллисекундах, а в пакетах. Каждый вызов * {@code spawnParticle} — это отдельный пакет всем игрокам в радиусе, плюс * сериализация и аллокация. Кольцо из 12 углов на 3 слоя было 36 вызовами с * count=1, то есть 36 пакетами на одно попадание; во взрыве — 72. * *
Смысл в том, что {@code spawnParticle} с count больше одного раскидывает * частицы случайно внутри объёма смещения. Поэтому кольцо радиуса r честно * превращается в заполненный диск того же радиуса. На масштабе половины блока * разница глазом не видна, а пакетов в разы меньше. * *
Числа частиц подобраны так, чтобы плотность осталась прежней: кольцо на * 12x3 становится тремя дисками по 12 частиц, то есть ровно те же 36 точек. */ public final class Particles { private Particles() { } /** Высота слоя кольца, как в исходной развёртке. */ private static final double LAYER_STEP = 0.25D; /** * Кольцо вокруг точки: {@code layers} вызовов вместо * {@code segments * layers}. */ public static void ring(World world, Location center, double radius, Particle.DustOptions dust, int segments, int layers) { ring(world, center, radius, dust, segments, layers, Particle.CRIT, 10); } public static void ring(World world, Location center, double radius, Particle.DustOptions dust, int segments, int layers, Particle spark, int sparkCount) { // Один диск на слой: offset задаёт полуразброс, поэтому частицы ложатся // в диск радиуса radius вокруг центра слоя, а не в точку. for (int h = 0; h < layers; h++) { final double y = center.getY() + ((h - (layers - 1) / 2.0D) * LAYER_STEP); final Location at = new Location(world, center.getX(), y, center.getZ()); world.spawnParticle(Particle.DUST, at, segments, radius, 0.0D, radius, 0.0D, dust); } if (spark != null && sparkCount > 0) { world.spawnParticle(spark, center, sparkCount, radius, radius * 0.5D, radius, 0.1D); } } /** Плоское кольцо на земле, как ударная волна. */ public static void groundRing(World world, Location center, double radius, Particle.DustOptions dust, int count) { world.spawnParticle(Particle.DUST, center, count, radius, 0.0D, radius, 0.0D, dust); } /** * Единичная частица без аллокаций на стороне вызывающего. * Обёртка существует только чтобы не плодить DustOptions в циклах — * объект переиспользуется, а не создаётся на каждую частицу. */ public static Particle.DustOptions dust(int r, int g, int b, float size) { return new Particle.DustOptions(Color.fromRGB(r, g, b), size); } }