Почему функция safeBreak () будет работать так, как ожидается при вызове 1, но не при вызове 2 или вызове 2.1?
Я работаю над своим плагином Minecraft Bukkit ToolBelt .
Один из инструментов (PickHax) в моем плагине позволяет игроку удалять блок, удерживая определенный материал (по умолчанию DIAMOND_PICKAXE). Чтобы обеспечить максимально широкую поддержку других плагинов, которые обеспечивают защиту региона (например, WorldGuard) и протоколирование (например, HawkEye), я создаю и вызываю BlockBreakEvent. Ниже приведен код, который делает это:
protected boolean safeBreak(Block target, Player subject, boolean applyPhysics) {
BlockBreakEvent canBreak = new BlockBreakEvent(target,subject);
server.getPluginManager().callEvent(canBreak);
if(!canBreak.isCancelled())
target.setTypeId(0, applyPhysics);
return !canBreak.isCancelled();
}
С текущей версией (0.1) ToolBelt это работает довольно хорошо, и не удаляет блок, если у игрока нет разрешения для этого региона сервера (WorldGuard). Я просто устанавливаю цель Блок на event.getClickedBlock()
, субъект Игрок на event.getPlayer()
, а логическое значение физики на true
, если они щелкнули левой кнопкой мыши, и false
если они щелкнули правой кнопкой мыши. Вот звонок в версии 0.1:
Звоните 1
safeBreak(target,event.getPlayer(),physics);
В настоящее время я работаю над новой версией, которая поддерживает удаление удаленных блоков. В зависимости от того, находится ли пользователь на корточках и имеет ли он узел разрешения диапазона, целевой блок устанавливается на event.getClickedBlock()
или subject.getTargetBlock(null,25)
. Это прекрасно работает за исключением одного случая.
- case 1 : Если они фактически щелкнули по блоку (LEFT_CLICK_BLOCK / RIGHT_CLICK_BLOCK), они увидят изменение с любыми настройками физики.
- case 2 : Если они получили блок на расстоянии и имеют физику
true
(LEFT_CLICK_AIR), то они видят изменение.
- case 3 : Однако, если они получили блок на расстоянии и имеют физику
false
(RIGHT_CLICK_AIR), тогда они не видят обновление блока на клиенте , Если они выходят из системы и снова включаются, изменения видны, поэтому изменения происходят на стороне сервера.
Чтобы устранить эту проблему, я попытался использовать subject.sendBlockChange()
, который должен посылать пользователю поддельные изменения блока, и никоим образом не изменять сервер. При этом пользователь всегда видит, что он сделал. Таким образом, новый код:
Звоните 2
if(safeBreak(target,event.getPlayer(),physics))
subject.sendBlockChange(target.getLocation(), 0, (byte)0);
Однако, по какой-то причине, изменение между просто выполнением safeBreak()
и выполнением if(safeBreak()) sendBlockChange()
делает так, что защита региона (WorldGuard) не соблюдается. Пользователь получает распечатку с WorldGuard, все еще предупреждая их, что у него нет прав на сборку, но блок все еще не работает.
Просто в случае, если описание для .sendBlockChange()
было неверным, оно фактически не меняет мир, я также попробовал его с «безвредным» печатным сообщением
Звоните 2,1
if(safeBreak(target,event.getPlayer(),physics))
subject.sendMessage("Error still present?");
Когда я запускаю Call 2.1, если я нахожусь в регионе, где у меня есть разрешение на разбиение блоков, я получаю «Ошибка все еще присутствует?» сообщение, но когда я нахожусь в запретной зоне, я не. Это означает, что safeBreak()
возвращает правильное значение, если я должен был разбить блок или нет, но каким-то образом все еще ломает блок. Кроме того, поскольку у него нет .sendBlockChange()
из Call 2, я снова получаю проблему случая 3.
Звоните 3
if(safeBreak(target,event.getPlayer(),physics)) {}
Теперь код не выполняет никаких действий, кроме проверки возвращаемого значения safeBreak()
, и все же он по-прежнему разбивает блоки в ограниченной области. Я переключился на Call 1, и он не сломал блоки в запретной зоне.
Это возвращает меня к первоначальному вопросу. Я могу перекомпилировать ToolBelt.jar с той лишь разницей, что Call 1 vs Call 2 и надежно воспроизвести проблему. Если вызов 1 установлен, поддержка региона соблюдается, но случай 3 не обновляет клиента. Если вызов 2 установлен, клиент всегда получает обновление блока, но он может удалить блоки в любом регионе.
Я могу обойти проблему, не допуская случай 3 (физическое удаление невозможно на расстоянии) и используя Call 1, однако я бы не хотел ставить под угрозу способность инструментов. Кто-нибудь знает, почему Call 2 и Call 2.1 не работают с регионами, когда Call 1 работает без проблем?
Интересующие ссылки на документацию:
Блок : Представляет блок.Это живой объект, и только один Блок может существовать для любого заданного местоположения в мире.
Player : представляет игрока, подключенного или нет
.isCanceled () : получает состояние отмены этого события.Отмененное событие не будет выполнено на сервере, но все равно будет передаваться другим плагинам
.sendBlockChange () : отправить изменение блока.Это подделывает пакет смены блока для пользователя в определенном месте.На самом деле это никак не изменит мир.