1. Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
    Скрыть объявление
Скрыть объявление
В преддверии глобального обновления, мы проводим исследования, которые помогут нам сделать опыт пользования форумом ещё удобнее. Помогите нам, примите участие!

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

Тема в разделе "Разработка плагинов для новичков", создана пользователем Copter533, 8 сен 2023.

  1. Автор темы
    Copter533

    Copter533 Участник Пользователь

    Баллы:
    31
    Имя в Minecraft:
    Copter533
    Можно ли как-нибудь запретить игроку взаимодействовать с миром и другими игроками, если он в гм 2? Начиная от подъёма предметов, заканчивая PVP. Paper 1.12.2
     
  2. NuaN

    NuaN Активный участник Пользователь

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

    Чтобы не забыть ничего, то лучше найти список всех ивентов в официальной документации.
     
  3. Bomb

    Bomb Активный участник Пользователь

    Баллы:
    76
    В данном случае думаю можно отменять не ивенты а пакеты.
    Входящих пакетов на взаимодействие гораздо меньше чем ивентов и шанс что-то забыть гораздо ниже.
    Правда придётся в некоторых случаях писать синхронизацию.
     
  4. Dymeth

    Dymeth Активный участник Пользователь

    Баллы:
    98
    Имя в Minecraft:
    Dymeth
    Время это не сэкономит
     
  5. Автор темы
    Copter533

    Copter533 Участник Пользователь

    Баллы:
    31
    Имя в Minecraft:
    Copter533
    Ну, вообщем, что-то такое я смог изобразить:


    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<Playerplayers = 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(evnull); }
        private 
    void cancel(Cancellable evEntity target) {
            if (
    target != null && !(target instanceof Player)) return;
            
    Player player = (Playertarget;

            if (
    player == null)
            for (
    String name : List.of("getPlayer""getEntity"))
                try {
                    
    Method method ev.getClass().getMethod(name);
                    
    player = (Playermethod.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(evev.getDamager()); }

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

        
    // @EventHandler private void event() {}
    }
    Оцените на сколько я говно кодер по шкале от 1 до 4.

    P.S.
    Кому надо, пусть забирает, я разрешаю.
     
  6. Sturm_PT

    Sturm_PT Активный участник Пользователь

    Баллы:
    76
    4
    Рефлексия медленная, а PlayerPickupItemEvent может вызываться каждый тик, TPS'у будет весело
     
  7. Автор темы
    Copter533

    Copter533 Участник Пользователь

    Баллы:
    31
    Имя в Minecraft:
    Copter533
    Вот переделка:

    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<Playerplayers = 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(evnull); }
        private 
    void cancel(Cancellable evEntity target) {
            if (
    target != null && !(target instanceof Player)) return;
            
    Player player = (Playertarget;

            if (
    player == null) {

                if (
    ev instanceof PlayerEventplayer = ((PlayerEventev).getPlayer();
                if (
    ev instanceof EntityEvent) {
                    
    Entity entity = ((EntityEventev).getEntity();
                    if (
    entity instanceof Playerplayer = (Playerentity;
                    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(evev.getPlayer()); }
        @
    EventHandler private void event(BlockPlaceEvent ev)            { cancel(evev.getPlayer()); }

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

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

        
    // @EventHandler private void event() {}
    }
     
  8. Dymeth

    Dymeth Активный участник Пользователь

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

    private <
    extends PlayerEvent Cancellablevoid cancel(T event) {
        
    cancel(eventevent.getPlayer());
    }

    private <
    extends EntityEvent Cancellablevoid cancel(T event) {
        
    cancel(eventevent.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
     
    Последнее редактирование: 13 сен 2023
  9. Автор темы
    Copter533

    Copter533 Участник Пользователь

    Баллы:
    31
    Имя в Minecraft:
    Copter533
    Спасибо за помощь!
     

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