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

Помогите Шедулер, таймер, ошибка.

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

Статус темы:
Закрыта.
  1. Автор темы
    second_vynder

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

    Баллы:
    153
    Skype:
    my.nik.vynder
    Код:
       public void DrawLottery(final int DelayTime, final int WinnersAmount){
            Bukkit.broadcastMessage(messagePrefix + messageLotteryStarts);
            if(DelayTime > 0){
                _DelayTime = DelayTime;
                timerTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){         
                    public void run()
                    {
                        if(_DelayTime <= 0){
                            Bukkit.getServer().getScheduler().cancelTask(timerTaskId);
                            DrawLotteryBody(DelayTime, WinnersAmount);
                            return;
                        }
                        Bukkit.broadcastMessage(messagePrefix +
                                messageTimeToStartLeft.replace("<time>",
                                Integer.toString(_DelayTime)));
                        _DelayTime--;
                    }
                }, 20L, 20L);
            }
            else DrawLotteryBody(DelayTime, WinnersAmount);
            timeRepeatableTaskId = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                @Override
                public void run() {
                    DrawLottery(timeBeforeBegin, amountOfWinners);
                }
            }, delay*20);
        }
    

    Проблема в том, что код
    Код:
                        if(_DelayTime <= 0){
                            Bukkit.getServer().getScheduler().cancelTask(timerTaskId);
                            DrawLotteryBody(DelayTime, WinnersAmount);
                            return;
                        }
    
    Исполняется пять раз вместо одного.
    И если кому-то поможет, то _DelayTime во всех пяти итерациях равен нулю.
     
    Последнее редактирование: 7 мар 2016
  2. Хостинг MineCraft
    <
  3. Автор темы
    second_vynder

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

    Баллы:
    153
    Skype:
    my.nik.vynder
    Ап, до сих пор солюшена не нашел, кому не трудно, помогите, пожалуйста.
     
  4. Reality_SC

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

    Баллы:
    123
    Имя в Minecraft:
    Reality_SC
    Ну например можно использовать runTask, вместо scheduleSyncRepeatingTask.
    P.S. Хотя нет. Блин, что-то думается сегодня тяжко :)

    Объясни на словах, что ты хочешь?
    Может отнимать от _DelayTime не 1, а 20, если оно у тебя в тиках?
     
  5. Автор темы
    second_vynder

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

    Баллы:
    153
    Skype:
    my.nik.vynder
    Мне необходим таймер. Методу передаются параметры, если один из них больше нуля (переменная задержки перед исполнением метода), то выполняется повторяемый таск, идет отсчет в секундах (таск запускается каждые 20 тиков, т.е. 20 секунд, соответственно, делей отнимается единожды за итерацию, т.е. отнимается одна секунда). Проблема в том, что код в таске исполняется некорректно, конкретнее, код в блоке IF, он должен исполняется единожды, останавливая повторение таска и вызывая новый метод, но вызывает он метод несколько раз. Опытным путем выяснил, что вызывает он метод в два раза меньшее количество раз, чем DelayTime. То есть если DelayTime = 10, то и код в блоке IF исполнится 5 раз, а если 20, то 10 раз. Очень странная зависимость.
    Прикреплю код целиком, если у кого-то есть свободное время поковырять чужой код.
    Начинать отслеживать рекомендую с конца метода OnEnable().
    Код:
    package me.vynder.commandlottery;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.logging.Logger;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import org.bukkit.plugin.java.JavaPlugin;
    import org.bukkit.Bukkit;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.configuration.InvalidConfigurationException;
    import org.bukkit.configuration.file.FileConfiguration;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.entity.Player;
    
    
    public class CommandLottery extends JavaPlugin {
    
        File settingsConfigFile;
        File languageConfigFile;
        FileConfiguration settingsConfig;
        FileConfiguration languageConfig;
        Boolean IsRepeatable;
        String messageLotteryStarts;
        String messageTimeToStartLeft;
        String messageWinToAll;
        String messageWinToWinner;
        String messageWinToAllMany;
        String messagePrefix;
        int amountOfWinners;
        int delay;
        int timeBeforeBegin;
        int minimalOnline;
        int timerTaskId;
        int timeRepeatableTaskId;
        List<?> commands;
        int _DelayTime;
      
        Logger log = getLogger();
      
        @Override
        public void onEnable() {
           settingsConfigFile = new File(getDataFolder(), "config.yml");
           languageConfigFile = new File(getDataFolder(), "language.yml");
           try {
               CreateConfigFiles();
           } catch (Exception e) {
               e.printStackTrace();
           }
           settingsConfig = new YamlConfiguration();
           languageConfig = new YamlConfiguration();
           try {
              settingsConfig.load(settingsConfigFile);
              languageConfig.load(languageConfigFile);
           } catch(IOException|InvalidConfigurationException e) {
              e.printStackTrace();
           }
          
           // Load all settings
           commands               = settingsConfig.getList("Commands");
           IsRepeatable           = settingsConfig.getBoolean("Global.RepeatEveryXTime");
           amountOfWinners        = settingsConfig.getInt("Global.WinnersAmount");
           delay                  = settingsConfig.getInt("Global.Delay");
           timeBeforeBegin        = settingsConfig.getInt("Global.TimeBeforeBegin");
           minimalOnline          = settingsConfig.getInt("Global.MinimalOnline");
           messageLotteryStarts   = languageConfig.getString("Global.LotteryStarts");
           messageLotteryStarts   = messageLotteryStarts.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
           messageTimeToStartLeft = languageConfig.getString("Global.LeftTime");
           messageTimeToStartLeft = messageTimeToStartLeft.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
           messageWinToAll        = languageConfig.getString("Global.WinToAll");
           messageWinToAll        = messageWinToAll.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
           messageWinToAllMany    = languageConfig.getString("Global.WinToAllMany");
           messageWinToAllMany    = messageWinToAllMany.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
           messageWinToWinner     = languageConfig.getString("Global.WinWinner");
           messageWinToWinner     = messageWinToWinner.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
           messagePrefix          = languageConfig.getString("Global.Prefix");
           messagePrefix          = messagePrefix.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
           if(IsRepeatable){
               timeRepeatableTaskId = Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                   @Override
                   public void run() {
                       DrawLottery(timeBeforeBegin, amountOfWinners);
                   }
               }, delay*20);
           }
        }
      
        @Override
        public void onDisable() {
        }
      
        public void CreateConfigFiles(){
            if(!settingsConfigFile.exists()){
                settingsConfigFile.getParentFile().mkdirs();
                copy(getResource("config.yml"), settingsConfigFile);
            }
            if(!languageConfigFile.exists()){
                languageConfigFile.getParentFile().mkdirs();
                copy(getResource("language.yml"), languageConfigFile);
            }
        }
      
        private void copy(InputStream in, File file) {
            try {
                OutputStream out = new FileOutputStream(file);
                byte[] buf = new byte[1024];
                int len;
                while((len=in.read(buf))>0){
                    out.write(buf,0,len);
                }
                out.close();
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
      
        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
            if(cmd.getName().equalsIgnoreCase("lotterydraw")){
                if(args.length !=2) return false;
                if(!args[0].isEmpty() && !args[1].isEmpty()){
                    int TimerToStart;
                    int WinrsAmt;
                    try{
                        TimerToStart = Integer.parseInt(args[0]);
                        WinrsAmt     = Integer.parseInt(args[1]);
                    }
                    catch(NumberFormatException e){
                        sender.sendMessage("Invalid argument!");
                        return false;
                    }
                    if(WinrsAmt < 0) return false;
                    if(WinrsAmt > Bukkit.getServer().getOnlinePlayers().size()){
                            sender.sendMessage("Amount of winners is bigger than online players!");
                            return true;
                    }
                    if(minimalOnline > Bukkit.getOnlinePlayers().size()){
                            sender.sendMessage("Minimal online to draw is " + minimalOnline);
                            return true;
                    }
                    DrawLotteryWithoutTimer(TimerToStart, WinrsAmt);
                }
                else return false;
            return true;
            }
          
            return false;
        }
    
        public void DrawLotteryWithoutTimer(final int DelayTime, final int WinnersAmount){
            Bukkit.broadcastMessage(messagePrefix + messageLotteryStarts);
            if(DelayTime > 0){
                _DelayTime = DelayTime;
                timerTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){
                    @Override
                    public void run()
                    {
                        if(_DelayTime <= 0){
                            Bukkit.getServer().getScheduler().cancelTask(timerTaskId);
                            DrawLotteryBody(WinnersAmount);
                            return;
                        }
                        Bukkit.broadcastMessage(messagePrefix +
                                messageTimeToStartLeft.replace("<time>",
                                Integer.toString(_DelayTime)));
                        _DelayTime--;
                    }
                }, 20L, 20L);
            }
            else DrawLotteryBody(WinnersAmount);
        }
        public void DrawLottery(final int DelayTime, final int WinnersAmount){
            if(minimalOnline <= Bukkit.getOnlinePlayers().size()){
                Bukkit.broadcastMessage(messagePrefix + messageLotteryStarts);
                if(DelayTime > 0){
                    _DelayTime = DelayTime;
                    timerTaskId = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){
                        @Override
                        public void run()
                        {
                            if(_DelayTime <= 0){
                                Bukkit.getServer().getScheduler().cancelTask(timerTaskId);
                                DrawLotteryBody(WinnersAmount);
                                return;
                            }
                            Bukkit.broadcastMessage(messagePrefix +
                                    messageTimeToStartLeft.replace("<time>",
                                            Integer.toString(_DelayTime)));
                            _DelayTime--;
                        }
                    }, 20L, 20L);
                }
                else DrawLotteryBody(WinnersAmount);
            }
                timeRepeatableTaskId = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                    @Override
                    public void run() {
                        DrawLottery(timeBeforeBegin, amountOfWinners);
                    }
                }, delay*20);
        }
      
        public void DrawLotteryBody(int WinnersAmount){
            ArrayList<Player> players = new ArrayList<Player>();
            for(Player player : Bukkit.getServer().getOnlinePlayers()){
                players.add(player);
            }
            ArrayList<Player> winners = new ArrayList<Player>();
            Random random = new Random();
            for(int i = 0; i < WinnersAmount; i++){
                try{
                int randomIndex = random.nextInt(players.size());
                winners.add(players.get(randomIndex));
                players.remove(randomIndex);
                }
                catch(IllegalArgumentException e){
                    log.info("Draw is unsuccesseful, someone left the game!");
                }
            }
            if(WinnersAmount == 1){
                Bukkit.broadcastMessage(messagePrefix +
                        messageWinToAll.replace("<player>", winners.get(0).getDisplayName()));
            }
            else{
                String formatted = "";
                for(Player player : winners){
                    formatted = formatted + player.getDisplayName();
                }
                Bukkit.broadcastMessage(messagePrefix +
                        messageWinToAllMany.replace("<players>", formatted));
            }
            String targetCommand = (String)commands.get(new Random().nextInt(commands.size()));
            for(Player player : winners){
                player.sendMessage(messagePrefix + messageWinToWinner);
                targetCommand = targetCommand.replace("<player>", player.getName());
                Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), targetCommand);
            }
        }
      
    }
    
    
     
  6. Dereku

    Dereku Старожил

    Баллы:
    173
    Skype:
    derek_unavailable
    Имя в Minecraft:
    _Dereku
    Храни значения (кол-во итераций) в HashMap, ибо твои оно нигде не хранятся толком.
     
  7. Reality_SC

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

    Баллы:
    123
    Имя в Minecraft:
    Reality_SC
    20 тиков = 1 секунда
    20 секунд = 400 тиков[DOUBLEPOST=1457462640,1457462592][/DOUBLEPOST]
    Завтра ковырну. Сегодня не то состояние :)[DOUBLEPOST=1457511559][/DOUBLEPOST]С одной стороны, автор явно шарит в Java и код более чем годный.
    С другой стороны, как-то всё сложно написано немного, с точки зрения логики. Сложно восстановить логику плагина в деталях, чтобы она сразу держалась в голове.
    Понятно, что лотерея должна запускаться при включении плагина, затем каждую секунду она смотрит, достаточно ли игроков онлайн чтобы начать лотерею, затем в течение некоторого времени визуально происходит розыгрыш, и в конце выдаются награды. Затем всё сразу заново. Плюс можно стартануть лотерею отдельно командой, что откладывает "таймерную" лотерею.
    Правильно ли я всё понял?
    time before begin — это от включения плагина до начала лотереи (и время между лотереями)?
    delay — это время от начала лотереи до объявления результатов?
    Код:
    .replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
    Это кастомный аналог ChatColors?[DOUBLEPOST=1457514259][/DOUBLEPOST]@second_vynder, в общем, я не тестировал, и не уверен, что оно работает так, как ты хотел, и что вообще работает, но попробуй разобраться в моём варианте деталей :) Мне кажется так проще.
    http://pastebin.com/zbJ6nyH6
     
    Последнее редактирование: 9 мар 2016
  8. Автор темы
    second_vynder

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

    Баллы:
    153
    Skype:
    my.nik.vynder
    Они нигде не хранятся и храниться не должны, мне заранее условно-известно, сколько итераций будет произведено, видимо, код Вы глянули мельком.

    Опечатался, да, 20 тиков = 1 секунда. А replaceAll() не мой, в строке по регулярке находятся все цветовые коды (&1, for ex.) и меняются на читаемые баккитом (& = знак параграфа). TimeBeforeBegin считывается с конфига, хранит стандартное время визуального отсчета (Объявление лотереи и проигрывание таймера в X сек, где X = TimeBeforeBegin). delay берется с конфига, содержит размер интервала между розыгрышом лотереи.

    Не могу говорить, что проблема решена, т.к. ничего я для этого не сделал по существу. Но я пересобрал плагин и работает он без нареканий. Видимо, возникает баг только при определенных условиях, которые я не в состоянии понять. В любом случае, всем отписавшимся спасибо за помощь.
     
Статус темы:
Закрыта.

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