Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.

Помогите Отмена всего

Copter533

Участник
Пользователь
Баллы
31
Имя в Minecraft
Copter533
Можно ли как-нибудь запретить игроку взаимодействовать с миром и другими игроками, если он в гм 2? Начиная от подъёма предметов, заканчивая PVP. Paper 1.12.2
 
Можно ли как-нибудь запретить игроку взаимодействовать с миром и другими игроками, если он в гм 2? Начиная от подъёма предметов, заканчивая PVP. Paper 1.12.2
Насколько я знаю, то нужно прописать в коде все возможные ивенты (установить блок, сломать блок, подобрать предмет, выкинуть предмет, кликнуть, ударить и таких еще десятки или даже сотни...). И вот в каждом из них нужно получать игрока, проверять какой у него gamemode и если это gamemode 2, то отменять ивент.

Чтобы не забыть ничего, то лучше найти список всех ивентов в официальной документации.
 
Насколько я знаю, то нужно прописать в коде все возможные ивенты (установить блок, сломать блок, подобрать предмет, выкинуть предмет, кликнуть, ударить и таких еще десятки или даже сотни...). И вот в каждом из них нужно получать игрока, проверять какой у него gamemode и если это gamemode 2, то отменять ивент.

Чтобы не забыть ничего, то лучше найти список всех ивентов в официальной документации.
В данном случае думаю можно отменять не ивенты а пакеты.
Входящих пакетов на взаимодействие гораздо меньше чем ивентов и шанс что-то забыть гораздо ниже.
Правда придётся в некоторых случаях писать синхронизацию.
 
В данном случае думаю можно отменять не ивенты а пакеты.
Входящих пакетов на взаимодействие гораздо меньше чем ивентов и шанс что-то забыть гораздо ниже.
Правда придётся в некоторых случаях писать синхронизацию.
Время это не сэкономит
 
Ну, вообщем, что-то такое я смог изобразить:


PHP:
package com.notcopter.notbedwars.handlers;

import com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.player.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CancelEverything implements Listener {
    private final Set<Player> players = new HashSet<>();

    public void addPlayer(Player player)    { players.add(player); }
    public void removePlayer(Player player) { players.remove(player); }
    public boolean hasPlayer(Player player) { return players.contains(player);}

    private void cancel(Cancellable ev) { cancel(ev, null); }
    private void cancel(Cancellable ev, Entity target) {
        if (target != null && !(target instanceof Player)) return;
        Player player = (Player) target;

        if (player == null)
        for (String name : List.of("getPlayer", "getEntity"))
            try {
                Method method = ev.getClass().getMethod(name);
                player = (Player) method.invoke(ev);
                break;
            } catch (Throwable ignored) {}

        if (player == null) return;
        if (hasPlayer(player)) ev.setCancelled(true);
    }

    @EventHandler private void event(PlayerPickupArrowEvent ev)     { cancel(ev); }
    @EventHandler private void event(PlayerPickupExperienceEvent ev){ cancel(ev); }
    @EventHandler private void event(EntityPickupItemEvent ev)      { cancel(ev); }
    @EventHandler private void event(PlayerDropItemEvent ev)        { cancel(ev); }

    @EventHandler private void event(PlayerInteractEvent ev)        { cancel(ev); }
    @EventHandler private void event(BlockBreakEvent ev)            { cancel(ev); }
    @EventHandler private void event(BlockPlaceEvent ev)            { cancel(ev); }

    @EventHandler private void event(EntityDamageEvent ev)          { cancel(ev); }
    @EventHandler private void event(FoodLevelChangeEvent ev)       { cancel(ev); }
    @EventHandler private void event(EntityDamageByEntityEvent ev)  { cancel(ev, ev.getDamager()); }

    @EventHandler private void event(PlayerArmorStandManipulateEvent ev) { cancel(ev); }

    // @EventHandler private void event() {}
}

Оцените на сколько я говно кодер по шкале от 1 до 4.

P.S.
Кому надо, пусть забирает, я разрешаю.
 
Ну, вообщем, что-то такое я смог изобразить:


PHP:
package com.notcopter.notbedwars.handlers;

import com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.player.*;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CancelEverything implements Listener {
    private final Set<Player> players = new HashSet<>();

    public void addPlayer(Player player)    { players.add(player); }
    public void removePlayer(Player player) { players.remove(player); }
    public boolean hasPlayer(Player player) { return players.contains(player);}

    private void cancel(Cancellable ev) { cancel(ev, null); }
    private void cancel(Cancellable ev, Entity target) {
        if (target != null && !(target instanceof Player)) return;
        Player player = (Player) target;

        if (player == null)
        for (String name : List.of("getPlayer", "getEntity"))
            try {
                Method method = ev.getClass().getMethod(name);
                player = (Player) method.invoke(ev);
                break;
            } catch (Throwable ignored) {}

        if (player == null) return;
        if (hasPlayer(player)) ev.setCancelled(true);
    }

    @EventHandler private void event(PlayerPickupArrowEvent ev)     { cancel(ev); }
    @EventHandler private void event(PlayerPickupExperienceEvent ev){ cancel(ev); }
    @EventHandler private void event(EntityPickupItemEvent ev)      { cancel(ev); }
    @EventHandler private void event(PlayerDropItemEvent ev)        { cancel(ev); }

    @EventHandler private void event(PlayerInteractEvent ev)        { cancel(ev); }
    @EventHandler private void event(BlockBreakEvent ev)            { cancel(ev); }
    @EventHandler private void event(BlockPlaceEvent ev)            { cancel(ev); }

    @EventHandler private void event(EntityDamageEvent ev)          { cancel(ev); }
    @EventHandler private void event(FoodLevelChangeEvent ev)       { cancel(ev); }
    @EventHandler private void event(EntityDamageByEntityEvent ev)  { cancel(ev, ev.getDamager()); }

    @EventHandler private void event(PlayerArmorStandManipulateEvent ev) { cancel(ev); }

    // @EventHandler private void event() {}
}

Оцените на сколько я говно кодер по шкале от 1 до 4.

P.S.
Кому надо, пусть забирает, я разрешаю.
4
Рефлексия медленная, а PlayerPickupItemEvent может вызываться каждый тик, TPS'у будет весело
 
Вот переделка:

PHP:
package com.notcopter.notbedwars.handlers;

import com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.player.*;

import java.util.HashSet;
import java.util.Set;

public class CancelEverything implements Listener {
    private final Set<Player> players = new HashSet<>();

    public void addPlayer(Player player)    { players.add(player); }
    public void removePlayer(Player player) { players.remove(player); }
    public boolean hasPlayer(Player player) { return players.contains(player);}

    private void cancel(Cancellable ev) { cancel(ev, null); }
    private void cancel(Cancellable ev, Entity target) {
        if (target != null && !(target instanceof Player)) return;
        Player player = (Player) target;

        if (player == null) {

            if (ev instanceof PlayerEvent) player = ((PlayerEvent) ev).getPlayer();
            if (ev instanceof EntityEvent) {
                Entity entity = ((EntityEvent) ev).getEntity();
                if (entity instanceof Player) player = (Player) entity;
                else return;
            }}

        if (player == null) return;
        if (hasPlayer(player)) ev.setCancelled(true);
    }

    @EventHandler private void event(PlayerPickupArrowEvent ev)     { cancel(ev); }
    @EventHandler private void event(PlayerPickupExperienceEvent ev){ cancel(ev); }
    @EventHandler private void event(EntityPickupItemEvent ev)      { cancel(ev); }
    @EventHandler private void event(PlayerDropItemEvent ev)        { cancel(ev); }

    @EventHandler private void event(PlayerInteractEvent ev)        { cancel(ev); }
    @EventHandler private void event(BlockBreakEvent ev)            { cancel(ev, ev.getPlayer()); }
    @EventHandler private void event(BlockPlaceEvent ev)            { cancel(ev, ev.getPlayer()); }

    @EventHandler private void event(EntityDamageEvent ev)          { cancel(ev); }
    @EventHandler private void event(FoodLevelChangeEvent ev)       { cancel(ev); }
    @EventHandler private void event(EntityDamageByEntityEvent ev)  { cancel(ev, ev.getDamager()); }

    @EventHandler private void event(PlayerArmorStandManipulateEvent ev) { cancel(ev); }

    // @EventHandler private void event() {}
}
 
PHP:
    private void cancel(Cancellable ev) { cancel(ev, null); }
    private void cancel(Cancellable ev, Entity target) {
        if (target != null && !(target instanceof Player)) return;
        Player player = (Player) target;

        if (player == null) {

            if (ev instanceof PlayerEvent) player = ((PlayerEvent) ev).getPlayer();
            if (ev instanceof EntityEvent) {
                Entity entity = ((EntityEvent) ev).getEntity();
                if (entity instanceof Player) player = (Player) entity;
                else return;
            }}

        if (player == null) return;
        if (hasPlayer(player)) ev.setCancelled(true);
    }
}

Отмену можно организовать более читабельно:
PHP:
private void cancel(Cancellable event, Entity entity) {
    if (entity instanceof Player player && hasPlayer(player)) {
        event.setCancelled(true);
    }
}

private <T extends PlayerEvent & Cancellable> void cancel(T event) {
    cancel(event, event.getPlayer());
}

private <T extends EntityEvent & Cancellable> void cancel(T event) {
    cancel(event, event.getEntity());
}



И ещё учти, что EntityDamageByEntityEvent также вызывается для зелий и Projectile (стрел, трезубцев, снежков). И event.getDamager() в таком случае вернёт не игрока, а непосредственно сущность, которая нанесла урон. Таким образом, при текущей реализации у игрока по-прежнему есть возможность наносить урон другим сущностям.

Поэтому нужно либо в событии получать "кидателя" этих самых зелий и проджектайлов, либо отменять сами события запуска проджектайлов и зелий.



Ну и хочу уточнить, что у игроков огромное количество разных отменяемых событий:
AsyncPlayerChatEvent
LootableInventoryReplenishEvent
PlayerAdvancementCriterionGrantEvent
PlayerAnimationEvent
PlayerAttackEntityCooldownResetEvent
PlayerAttemptPickupItemEvent
PlayerBedEnterEvent
PlayerBedFailEnterEvent
PlayerBedLeaveEvent
PlayerBucketEntityEvent
PlayerBucketEvent
PlayerChangeBeaconEffectEvent
PlayerChatEvent
PlayerCommandPreprocessEvent
PlayerDeepSleepEvent
PlayerDropItemEvent
PlayerEditBookEvent
PlayerElytraBoostEvent
PlayerFishEvent
PlayerFlowerPotManipulateEvent
PlayerGameModeChangeEvent
PlayerHarvestBlockEvent
PlayerInteractEntityEvent
PlayerInteractEvent
PlayerItemConsumeEvent
PlayerItemCooldownEvent
PlayerItemDamageEvent
PlayerItemFrameChangeEvent
PlayerItemHeldEvent
PlayerItemMendEvent
PlayerJumpEvent
PlayerKickEvent
PlayerLaunchProjectileEvent
PlayerLecternPageChangeEvent
PlayerLoomPatternSelectEvent
PlayerMoveEvent
PlayerNameEntityEvent
PlayerNaturallySpawnCreaturesEvent
PlayerOpenSignEvent
PlayerPickItemEvent
PlayerPickupExperienceEvent
PlayerPickupItemEvent
PlayerPurchaseEvent
PlayerReadyArrowEvent
PlayerRecipeBookClickEvent
PlayerRecipeDiscoverEvent
PlayerSetSpawnEvent
PlayerShearBlockEvent
PlayerShearEntityEvent
PlayerSignOpenEvent
PlayerSpawnChangeEvent
PlayerStartSpectatingEntityEvent
PlayerStatisticIncrementEvent
PlayerStonecutterRecipeSelectEvent
PlayerStopSpectatingEntityEvent
PlayerSwapHandItemsEvent
PlayerTakeLecternBookEvent
PlayerToggleFlightEvent
PlayerToggleSneakEvent
PlayerToggleSprintEvent
PlayerTrackEntityEvent
PlayerVelocityEvent
PrePlayerAttackEntityEvent
Источник: https://jd.papermc.io/paper/1.20/org/bukkit/event/player/PlayerEvent.html

И это только наследники PlayerEvent. А есть и другие события, взаимодействующие с игроками - как тот же EntityDamageEvent. На Spigot 1.12 их меньше, но всё равно много.

Но, к счастью, использовать абсолютно все события смысла нет. Самые необходимые можно найти в плагинах на авторизацию (например, в AuthMe): https://github.com/AuthMe/AuthMeReloaded/tree/master/src/main/java/fr/xephi/authme/listener
 
Последнее редактирование:
Отмену можно организовать более читабельно:
PHP:
private void cancel(Cancellable event, Entity entity) {
    if (entity instanceof Player player && hasPlayer(player)) {
        event.setCancelled(true);
    }
}

private <T extends PlayerEvent & Cancellable> void cancel(T event) {
    cancel(event, event.getPlayer());
}

private <T extends EntityEvent & Cancellable> void cancel(T event) {
    cancel(event, event.getEntity());
}



И ещё учти, что EntityDamageByEntityEvent также вызывается для зелий и Projectile (стрел, трезубцев, снежков). И event.getDamager() в таком случае вернёт не игрока, а непосредственно сущность, которая нанесла урон. Таким образом, при текущей реализации у игрока по-прежнему есть возможность наносить урон других сущностям.

Поэтому нужно либо в событии получать "кидателя" этих самых зелий и проджектайлов, либо отменять сами события запуска проджектайлов и зелий.



Ну и хочу уточнить, что у игроков огромное количество разных отменяемых событий:
AsyncPlayerChatEvent
LootableInventoryReplenishEvent
PlayerAdvancementCriterionGrantEvent
PlayerAnimationEvent
PlayerAttackEntityCooldownResetEvent
PlayerAttemptPickupItemEvent
PlayerBedEnterEvent
PlayerBedFailEnterEvent
PlayerBedLeaveEvent
PlayerBucketEntityEvent
PlayerBucketEvent
PlayerChangeBeaconEffectEvent
PlayerChatEvent
PlayerCommandPreprocessEvent
PlayerDeepSleepEvent
PlayerDropItemEvent
PlayerEditBookEvent
PlayerElytraBoostEvent
PlayerFishEvent
PlayerFlowerPotManipulateEvent
PlayerGameModeChangeEvent
PlayerHarvestBlockEvent
PlayerInteractEntityEvent
PlayerInteractEvent
PlayerItemConsumeEvent
PlayerItemCooldownEvent
PlayerItemDamageEvent
PlayerItemFrameChangeEvent
PlayerItemHeldEvent
PlayerItemMendEvent
PlayerJumpEvent
PlayerKickEvent
PlayerLaunchProjectileEvent
PlayerLecternPageChangeEvent
PlayerLoomPatternSelectEvent
PlayerMoveEvent
PlayerNameEntityEvent
PlayerNaturallySpawnCreaturesEvent
PlayerOpenSignEvent
PlayerPickItemEvent
PlayerPickupExperienceEvent
PlayerPickupItemEvent
PlayerPurchaseEvent
PlayerReadyArrowEvent
PlayerRecipeBookClickEvent
PlayerRecipeDiscoverEvent
PlayerSetSpawnEvent
PlayerShearBlockEvent
PlayerShearEntityEvent
PlayerSignOpenEvent
PlayerSpawnChangeEvent
PlayerStartSpectatingEntityEvent
PlayerStatisticIncrementEvent
PlayerStonecutterRecipeSelectEvent
PlayerStopSpectatingEntityEvent
PlayerSwapHandItemsEvent
PlayerTakeLecternBookEvent
PlayerToggleFlightEvent
PlayerToggleSneakEvent
PlayerToggleSprintEvent
PlayerTrackEntityEvent
PlayerVelocityEvent
PrePlayerAttackEntityEvent
Источник: https://jd.papermc.io/paper/1.20/org/bukkit/event/player/PlayerEvent.html

И это только наследники PlayerEvent. А есть и другие события, взаимодействующие с игроками - как тот же EntityDamageEvent. На Spigot 1.12 их меньше, но всё равно много.

Но, к счастью, использовать абсолютно все события смысла нет. Самые необходимые можно найти в плагинах на авторизацию (например, в AuthMe): https://github.com/AuthMe/AuthMeReloaded/tree/master/src/main/java/fr/xephi/authme/listener
Спасибо за помощь!
 

Поделиться этой страницей

Назад
Верх