feat(voiddeath): muffled death in the void, local message only
Одиннадцатый этап, последний из задуманных. Сообщение о смерти в пустоте не уходит в общий чат: забирается через deathMessage(null) и отправляется только тем, кто в радиусе 100 блоков от места смерти. Текст сообщения при этом тот же самый, что и обычно. Убийство кого-то отдельным обработчиком ловить не пришлось: «X убит Y» — это то же самое событие PlayerDeathEvent, что и «X умер». Различаются они только текстом, который и так передаётся как есть. Крик визера: громкость 0.2, дальность доставки 150 блоков. Отдельного ENTITY_WITHER_SCREAM в enum нет — визer's крик в ванилле называется entity.wither.spawn, то есть ENTITY_WITHER_SPAWN. Про «дальность 150» честно: это радиус доставки пакета на сервере, то есть кто его вообще получил. Громкость 0.2 — громкость пакета, а клиент дальше применяет своё позиционное затухание: у источника слышно, в сотне метров почти нет. Чтобы звук был одинаково громким на всех 150 блоках, громкость пришлось бы поднять до 9.4, и тогда заглушало бы всех рядом с источником. Именно для такой задачи в Delta есть раздельная дальность звука, и флаг decoupled-sound-range-enabled на проде включён: без него World#playSound с радиусом молча уходит в стоковое поведение, где радиус выводится из громкости, то есть 0.2 даёт 3.2 блока. Проверено: плагин грузится без ошибок, флаг виден в /delta как true. Сама смерть в пустоте не проверялась — нужен игрок.
This commit is contained in:
@@ -49,6 +49,7 @@ public class BlackKnifePlugin extends JavaPlugin {
|
|||||||
getServer().getPluginManager().registerEvents(new MoleHoleCoords(this), this);
|
getServer().getPluginManager().registerEvents(new MoleHoleCoords(this), this);
|
||||||
getServer().getPluginManager().registerEvents(new VoidWorld(), this);
|
getServer().getPluginManager().registerEvents(new VoidWorld(), this);
|
||||||
getServer().getPluginManager().registerEvents(new VoidExit(), this);
|
getServer().getPluginManager().registerEvents(new VoidExit(), this);
|
||||||
|
getServer().getPluginManager().registerEvents(new VoidDeath(), this);
|
||||||
BlackKnife.init(this);
|
BlackKnife.init(this);
|
||||||
// Имя измерения сервер выбирает сам, поэтому угадывать его в коде нельзя.
|
// Имя измерения сервер выбирает сам, поэтому угадывать его в коде нельзя.
|
||||||
// Находим и печатаем: по этой строке видно, какой мир считается пустотой.
|
// Находим и печатаем: по этой строке видно, какой мир считается пустотой.
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package me.sashegdev.blackknife;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.SoundCategory;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Глухая смерть в пустоте.
|
||||||
|
*
|
||||||
|
* <p>По условию: в пустоте сообщение о смерти не уходит в общий чат, а достаёт
|
||||||
|
* только тех, кто рядом — в радиусе 100 блоков. Вместо сообщения слышен крик
|
||||||
|
* визера: громкость 0.2 от обычной, дальность 150 блоков. Убийство кого-то
|
||||||
|
* трактуется так же, как собственная смерть.
|
||||||
|
*
|
||||||
|
* <p>Убийство отдельным обработчиком ловить не нужно: сообщение «X убит Y»
|
||||||
|
* это то же самое событие {@link PlayerDeathEvent}, что и «X умер». Один
|
||||||
|
* обработчик покрывает оба случая, а различаются они только текстом сообщения,
|
||||||
|
* который мы и так передаём как есть.
|
||||||
|
*
|
||||||
|
* <p>Про «дальность 150» и «громкость 0.2» стоит понимать честно: 150 — это
|
||||||
|
* радиус доставки пакета на сервере, то есть кто его вообще получит. Громкость
|
||||||
|
* 0.2 — громкость самого пакета. Клиент дальше применяет своё позиционное
|
||||||
|
* затухание, поэтому вблизи источника звук слышен, а в сотне метров — уже
|
||||||
|
* почти нет. Сделать его одинаково громким на все 150 блоков можно было бы
|
||||||
|
* только громкостью от 9.4, и тогда заглушало бы всех, кто стоит рядом.
|
||||||
|
*/
|
||||||
|
public final class VoidDeath implements Listener {
|
||||||
|
|
||||||
|
public VoidDeath() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Радиус, в котором сообщение о смерти ещё слышно. */
|
||||||
|
public static final double MESSAGE_RADIUS = 100.0D;
|
||||||
|
/** Дальность доставки звука, блоков. */
|
||||||
|
public static final float SOUND_RANGE = 150.0F;
|
||||||
|
/** Громкость крика визера. */
|
||||||
|
public static final float SOUND_VOLUME = 0.2F;
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onDeath(PlayerDeathEvent e) {
|
||||||
|
final Player victim = e.getEntity();
|
||||||
|
if (!VoidWorld.inVoid(victim)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Забираем сообщение из общего чата. null означает «не показывать».
|
||||||
|
final Component message = e.deathMessage();
|
||||||
|
e.deathMessage(null);
|
||||||
|
|
||||||
|
final Location at = victim.getLocation();
|
||||||
|
final double r2 = MESSAGE_RADIUS * MESSAGE_RADIUS;
|
||||||
|
|
||||||
|
// Локально — только тем, кто рядом с местом смерти.
|
||||||
|
for (Player p : victim.getWorld().getPlayers()) {
|
||||||
|
if (p.getLocation().distanceSquared(at) <= r2 && message != null) {
|
||||||
|
p.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Крик визера. Отдельного ENTITY_WITHER_SCREAM в enum нет: визer's
|
||||||
|
// крик в ванилле называется entity.wither.spawn.
|
||||||
|
victim.getWorld().playSound(at, Sound.ENTITY_WITHER_SPAWN,
|
||||||
|
SoundCategory.HOSTILE, SOUND_VOLUME, 1.0F, SOUND_RANGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user