Войти или зарегистрироваться

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

Статус
Закрыто для дальнейших ответов.

second_vynder

Старожил
Пользователь
Баллы
153
Java:
   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);
    }

Проблема в том, что код
Java:
                    if(_DelayTime <= 0){
                        Bukkit.getServer().getScheduler().cancelTask(timerTaskId);
                        DrawLotteryBody(DelayTime, WinnersAmount);
                        return;
                    }
Исполняется пять раз вместо одного.
И если кому-то поможет, то _DelayTime во всех пяти итерациях равен нулю.
 
Последнее редактирование:
Ап, до сих пор солюшена не нашел, кому не трудно, помогите, пожалуйста.
 
Ну например можно использовать runTask, вместо scheduleSyncRepeatingTask.
P.S. Хотя нет. Блин, что-то думается сегодня тяжко :)

Объясни на словах, что ты хочешь?
Может отнимать от _DelayTime не 1, а 20, если оно у тебя в тиках?
 
Мне необходим таймер. Методу передаются параметры, если один из них больше нуля (переменная задержки перед исполнением метода), то выполняется повторяемый таск, идет отсчет в секундах (таск запускается каждые 20 тиков, т.е. 20 секунд, соответственно, делей отнимается единожды за итерацию, т.е. отнимается одна секунда). Проблема в том, что код в таске исполняется некорректно, конкретнее, код в блоке IF, он должен исполняется единожды, останавливая повторение таска и вызывая новый метод, но вызывает он метод несколько раз. Опытным путем выяснил, что вызывает он метод в два раза меньшее количество раз, чем DelayTime. То есть если DelayTime = 10, то и код в блоке IF исполнится 5 раз, а если 20, то 10 раз. Очень странная зависимость.
Прикреплю код целиком, если у кого-то есть свободное время поковырять чужой код.
Начинать отслеживать рекомендую с конца метода OnEnable().
Java:
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);
        }
    }
  
}
 
Мне необходим таймер. Методу передаются параметры, если один из них больше нуля (переменная задержки перед исполнением метода), то выполняется повторяемый таск, идет отсчет в секундах (таск запускается каждые 20 тиков, т.е. 20 секунд, соответственно, делей отнимается единожды за итерацию, т.е. отнимается одна секунда). Проблема в том, что код в таске исполняется некорректно, конкретнее, код в блоке IF, он должен исполняется единожды, останавливая повторение таска и вызывая новый метод, но вызывает он метод несколько раз. Опытным путем выяснил, что вызывает он метод в два раза меньшее количество раз, чем DelayTime. То есть если DelayTime = 10, то и код в блоке IF исполнится 5 раз, а если 20, то 10 раз. Очень странная зависимость.
Прикреплю код целиком, если у кого-то есть свободное время поковырять чужой код.
Храни значения (кол-во итераций) в HashMap, ибо твои оно нигде не хранятся толком.
 
20 тиков, т.е. 20 секунд
20 тиков = 1 секунда
20 секунд = 400 тиков
Прикреплю код целиком, если у кого-то есть свободное время поковырять чужой код.
Завтра ковырну. Сегодня не то состояние :)
С одной стороны, автор явно шарит в Java и код более чем годный.
С другой стороны, как-то всё сложно написано немного, с точки зрения логики. Сложно восстановить логику плагина в деталях, чтобы она сразу держалась в голове.
Понятно, что лотерея должна запускаться при включении плагина, затем каждую секунду она смотрит, достаточно ли игроков онлайн чтобы начать лотерею, затем в течение некоторого времени визуально происходит розыгрыш, и в конце выдаются награды. Затем всё сразу заново. Плюс можно стартануть лотерею отдельно командой, что откладывает "таймерную" лотерею.
Правильно ли я всё понял?
time before begin — это от включения плагина до начала лотереи (и время между лотереями)?
delay — это время от начала лотереи до объявления результатов?
Java:
.replaceAll("(?i)&([a-k0-9])", "\u00A7$1");
Это кастомный аналог ChatColors?
@second_vynder, в общем, я не тестировал, и не уверен, что оно работает так, как ты хотел, и что вообще работает, но попробуй разобраться в моём варианте деталей :) Мне кажется так проще.
http://pastebin.com/zbJ6nyH6
 
Последнее редактирование:
Храни значения (кол-во итераций) в HashMap, ибо твои оно нигде не хранятся толком.
Они нигде не хранятся и храниться не должны, мне заранее условно-известно, сколько итераций будет произведено, видимо, код Вы глянули мельком.

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

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