Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Dismiss Notice

Помогите Как сделать задержку?

Discussion in 'Разработка плагинов для новичков' started by CHAMPION, Nov 9, 2015.

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

    CHAMPION Ньюби Пользователь

    Trophy Points:
    1
    Имя в Minecraft:
    ReeTap
    Тупой вопрос, но...
    Как сделать задержку между этими командами?)
    Т.е, мне нужно чтобы сначала выполнилась первая команда, и через 10 секунд вторая
    player.getInventory().addItem(new ItemStack(Material.DIAMOND_BLOCK));
    player.getInventory().addItem(new ItemStack(Material.CAKE));
     
  2. Хостинг MineCraft
    <
  3. _EnderWorld_

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

    Trophy Points:
    78
    Имя в Minecraft:
    Steve
    Во первых этот код это не команда.
    Конструктор команды делается вот так:
    Code:
    public boolean onTest(CommandSender sender, Command cmd, String label, String[] args) {
    
    Player p = (Player) sender;                       // Узнаем что игрок отправитель команды
    
    if(!(p.hasPermission("Твой пермишен"))) {               // Если игрок не имеет право
             return;                                   // Возвращаем действия
    }
     
    if(label.equalsIgnoreCase("Твоя команда тут") {          // Узнаем какая команда будет выдавать код
    
          // Твой код здесь
    
    }
    
    
    
    return false;
    
    
     
  4. Reality_SC

    Reality_SC Старожил Пользователь

    Trophy Points:
    123
    Имя в Minecraft:
    Reality_SC
    Code:
    ...
    player.getInventory().addItem(new ItemStack(Material.DIAMOND_BLOCK));
    getServer().getScheduler().runTaskLater(new Runnable()
    {
       @Override
       public void run()
       {
          player.getInventory().addItem(new ItemStack(Material.CAKE));
       }
    }, 20 * 10);
    Писал без IDE, мог косячнуть.
     
  5. Автор темы
    CHAMPION

    CHAMPION Ньюби Пользователь

    Trophy Points:
    1
    Имя в Minecraft:
    ReeTap
    Кучу ошибок выдаёт, не могу их убрать)[DOUBLEPOST=1447059690,1447059649][/DOUBLEPOST]
    Мне нужно сделать задержку, а не пермишены проверить)
     
  6. Reality_SC

    Reality_SC Старожил Пользователь

    Trophy Points:
    123
    Имя в Minecraft:
    Reality_SC
    Чтобы убрать ошибку, нужно её понять.
     
  7. DPOH-VAR

    DPOH-VAR Старожил Пользователь

    Trophy Points:
    153
    Skype:
    dpohvar
    1) Не надо проверять пермиты на команду в коде команды.
    Потому что это конфигурякается в plugin.yml.
    Проверку пермитов нужно делать только при сложной логике.
    Если вы видели такой подход в туториалах - забудьте, эта проверка лишняя.

    2) Не надо проверять название команды.
    Потому что это тоже конфигурякается в plugin.yml.
    Имя команды и ее алиасы задаются в конфиге. Если код исполняется, значит он вызван по вашей команде или по алиасу.
    Проверку имени команды надо делать только в случаях:
    • если вам нужно отличать название команды или алиасов, что не требуется в 99% случаев.
    • если вы говнокодите и вешаете один и тот же обработчик на две разных команды.
    • если вы используете два разных инстанса одного класса как обработчики двух разных команд. Но тогда поведение должно зависеть от свойств инстанса, а не от названия команды.
    Если вы видели такой подход в туториалах - забудьте, эта проверка лишняя.

    3) Player p = (Player) sender;
    Всегда предусматривайте возможность того, что команду может исполнить не только игрок.
    А вот тут точно нужна проверка класса. Или, если любите говнокодить, то try-catch
    Простой вариант:
    Code:
    if (!(sender instanceof Player) return false)
    4) public boolean onTest
    Всё-таки onCommand
    И метод всегда должен возвращать булево:
    true - наша команда отработала как надо, все ок.
    false - произошла ошибка. Sender автоматически получит сообщение со справкой о команде.

    Учтите, что метод runTaskLater добавляет задачу в планировщик. Задача добавится, однако остальной код (ниже) продолжит исполняться сейчас.
     
  8. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    THIS.
    Хоть кто то догадался это написать. Я б даже лайк поставил. Два лайка.
     
  9. LaoTheLizard

    LaoTheLizard Старожил Пользователь

    Trophy Points:
    103
    Skype:
    sgp_the_controller
    Кстати, эти ошибки делает большинство.
     
  10. SaMEC

    SaMEC Старожил Пользователь

    Trophy Points:
    173
    Skype:
    support.meedway
    Имя в Minecraft:
    Nick
    Вот вам шаблончик, для создания задержки другим способом.
    Code:
    package ru.meedway.samec;
    
    import java.util.HashMap;
    
    public class Cooldown {
        private String player;
        private long cooldown;
        private String key;
        public static HashMap<String, Cooldown> cooldowns = new HashMap();
       
        public Cooldown(String player, long cooldown, String key){
            this.player = player;
            this.cooldown = cooldown;
            this.key = key;
        }
       
        public String getPlayer(){
            return this.player;
        }
       
        public long getCooldown(){
            return this.cooldown;
           
        }
       
        public String getKey(){
            return this.key;
        }
       
        public static void setCooldown(String player, long cooldown, String title){
            cooldowns.put(player + title, new Cooldown(player, System.currentTimeMillis()+ cooldown, title));
        }
       
        public static boolean hasCooldown(String player, String title){
            if(cooldowns.get(player + title) == null){
                return false;
            }
            return ((Cooldown)cooldowns.get(player + title)).getCooldown() > System.currentTimeMillis();
        }
       
        public static long getCooldown(String player, String title){
            return ((Cooldown)cooldowns.get(player + title)).getCooldown() - System.currentTimeMillis();
        }
    }
    
    После просто вставляете куда вам вздумается, данную конструкцию, просто меняя название таблицы.
    Code:
    
            if(Cooldown.hasCooldown(player.getName(), "guns")){
                player.sendMessage("Ожидайте " + Cooldown.getCooldown(player.getName(), "guns"));
                e.setCancelled(true);
                return;
            }
          Cooldown.setCooldown(player.getName(), 5 * 1000L, "guns");
    
    Меньше нагрузка, по сравнению с Scheduler.
     
  11. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Не вижу никаких runnable. Отсюда выходит, что данный код должен чем то вызываться. Костыль для Scheduler, который будет использоваться Scheduler'ом?
     
  12. DPOH-VAR

    DPOH-VAR Старожил Пользователь

    Trophy Points:
    153
    Skype:
    dpohvar
    Это кулдаун. Ну или паттерн throttle without trailing.
    В определенном месте ставится семафор с таймером и исполняется код. При следующем вызове, если семафор установлен, код не исполняется. Предназначение совсем другое, не то, что имел в виду ТС.
     
  13. CraftCoder

    CraftCoder Старожил Пользователь

    Trophy Points:
    108
    Имя в Minecraft:
    CraftCoderr
    Если у нескольких команд один executor, то проверять нужно.
     
  14. DPOH-VAR

    DPOH-VAR Старожил Пользователь

    Trophy Points:
    153
    Skype:
    dpohvar
    Повторю: это основная ошибка новичков.

    Юный девелопер, который решил заняться плагинами, и абсолютно не знаком с java, сделает свой первый Hello world путём копипасты из туториала. Сам туториал, к сожалению, ничего толком не объясняет, а просто указывает, как нужно писать, при этом сам состоит из говнокода.
    Всё, на что опирается новичок - это конструкции языка: if, for, while и другие. На них можно построить всю логику плагина, но этого недостаточно, чтобы писать хороший, человекочитаемый и поддерживаемый код.

    Проблема туториалов в том, что там не объясняется архитектура Bukkit API. К примеру приведу инструкцию по созданию обработчика команд:
    - Создай класс MyExecutor implements CommandExecutor
    - зарегистрируй его так: getCommand("basic").setExecutor(new MyExecutor());
    - Создай в нем метод onCommand и напишите в него говнокод как в туториале
    Всё. Этого достаточно, все будет работать.

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

    давайте реализуем команды /sendRed и /sendBlue, которые будут писать сообщение в чат красным и синим цветом соответственно.
    Решение в лоб, как поступит новичок:
    Code:
    // Plugin onload:
    getCommand("sendRed").setExecutor(new ColorExecutor());
    getCommand("sendBlue").setExecutor(new ColorExecutor());
    // ColorExecutor:
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
        if (args.length >= 1) {
            if (cmd.getName().equals("sendRed")){
               sender.sendMessage(ChatColor.RED.toString() + args[0])
               return true;
           }
           if (cmd.getName().equals("sendBlue")){
               sender.sendMessage(ChatColor.RED.toString() + args[0])
               return true;
           }
        }
        return false;
    }
    а вот более практичный способ:
    Code:
    // Plugin onload:
    getCommand("sendRed").setExecutor(new ColorExecutor(ChatColor.RED));
    getCommand("sendBlue").setExecutor(new ColorExecutor(ChatColor.BLUE));
    // ColorExecutor:
    private ChatColor color;
    public ColorExecutor(ChatColor color){
        this.color = color;
    }
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
        if (args.length < 1) return false;
        sender.sendMessage(this.color.toString() + args[0])
        return true;
    }
    Таким образом, если в будущем вам приспичит создать команду /sendYellow, достаточно будет всего лишь добавить ее в plugin.yml и прописать
    Code:
    getCommand("sendYellow").setExecutor(new ColorExecutor(ChatColor.YELLOW));
    и не нужно править код листенера.

    PS: Этот код скорее бесполезный. Есть еще много способов улучшить этот код, и не нужно на эту тему холиварить. Основной идеей было то, что практичность кода больше зависит от опыта программиста, чем от реализации API, и этого невозможно добиться, изучая только туториалы.

    PSS: Есть еще и другие способы зарегистрировать команду, кроме как через setExecutor(CommandExecutor). Например, чтобы не прописывать команду в plugin.yml вовсе. Но это требуется далеко не всем плагинам и требует хороших знаний Bukkit API.

    Если вы пишете один обработчик для нескольких команд, то:
    • либо вы говнокодите от недостатка знаний ООП. У вас получится сильносвязанный код, содержащий потенциальные ошибки при его изменении и переиспользовании.
    • либо вы делаете как в примере выше, и вас не волнует название команды внутри обработчика
    Выводы такие:
    • Изучайте язык, а не только его синтаксис.
    • Не опирайтесь на туториал полностью. В реальной практике туториалы бесполезны. Читайте доки по Bukkit API.
    • Экспериментируйте! Опыт растет не в бороде, а на руках.
    • Еще раз изучайте язык и пишите хороший слабосвязаный человекочитаемый код.
     
    Last edited: Nov 11, 2015
  15. Dolikan

    Dolikan Ньюби Пользователь

    Trophy Points:
    1
    Честно, говоря, обработка команд - одна из главных проблем в Bukkit API. У меня нередко выходит говнокод именно в командах из-за всяких проверок аргументов, прав, подкомманд, кто отправил и т.д.

    Чтобы навести порядок в командах, стоит использовать либу от sk89q.
     
  16. Dereku

    Dereku Старожил

    Trophy Points:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Можно обойтись и без неё, если грамотно форматировать код.
     

Share This Page