迭代文本,它们之间有不同的长度延迟

时间:2016-10-21 05:34:52

标签: java loops runnable bukkit

  • Bukkit / Spigot API - https://hub.spigotmc.org/javadocs/spigot/
    好的,我正在尝试为我的服务器制作教程系统。我经常看到人们显示这样的文字:

    public void send(String...strings) {
        for (String string : strings) {
            player.sendMessage(string);
        }
    }
    

    ..这太可怕了。如您所知,它会对聊天进行垃圾邮件并使其无法读取 因此,我使用runnables以一定的延迟显示文本。我可以轻松地使用相同的特定延迟(即30个滴答)进行运行,但我喜欢runnable基于String的length()进行延迟。

    我试着这样做:

    public void send(String...strings) {
        for (String string : strings) {
            new BukkitRunnable() {
                @Override
                public void run() {
                    player.sendMessage(string);
                }
            }.runTaskLater(my_plugin_instance, (string.length()*2));
        }
    }
    

    有了这个,是的,它需要字符串的长度,但是for loop在runnable显示文本之前继续到下一个字符串。
    所以如果我有这些句子(按照正确的顺序):

    • Welcome to the server, player!
    • This server is about blablabla, this and that and a bit more of that and this
    • Accept the tutorial?


    订单将是

    • Accept the tutorial?
    • Welcome to the server, player!
    • This server is about blablabla, this and that and a bit more of that and this

    我该怎么办?

3 个答案:

答案 0 :(得分:1)

您可能需要考虑使用单个对象(即Singleton)作为打印机来打印所有消息。这样可以避免创建过多的线程。

下面的解决方案使用BlockingQueue以使打印线程等待下一条消息。当消息不在队列中时 - run()方法将等待而不会消耗太多CPU。

解决方案有两种形式: - 如果你取消注释第一个msgQueue - 你将获得sendMessage的阻塞行为;该方法将一直等到所有项目都打印出来。 - 如果您推荐第二个msgQueue - 消息将被添加到队列中而无需等待打印。

我添加了ExecutorService来管理Thread,因为Oracle / Java认为这是使用ExecutorServices管理线程的一个好习惯。一旦不需要MessagePrinter,它就会被“executor.shutdownNow();”发出信号。和平地完成。

希望这有帮助。

package stackoverflow;

import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

class MessagePrinter implements Runnable {

    private static MessagePrinter instance;
    private MessagePrinter() {};

    // Uncomment the one below to make sendText wait until methods until all items are printed:
    // BlockingQueue<String> msgQueue = new LinkedBlockingQueue<>(1);

    // Uncomment the one below to make sendText not wait until messages are printed:
    BlockingQueue<String> msgQueue = new LinkedBlockingQueue<>(1);

    public void run() {
        try {
            while (true) { 
                String str = msgQueue.take();
                Thread.sleep( str.length() );
                TimeUnit.MILLISECONDS.sleep( str.length() * 10 );

                System.out.println(str);
            }
        } catch (InterruptedException e) {
            System.out.println("Quitting...");
            return;
        }
    }

    public void sendText(String... txt) {
        Arrays.asList(txt).stream().forEach(t -> {
            try {
                msgQueue.put(t);
            } catch (InterruptedException e) {
                // Received request to terminate.
                return;
            }
        });
    }

    synchronized public static MessagePrinter getInstance() {
        if (instance == null)
            instance = new MessagePrinter();
        return instance;
    }
}

public class VarDelay {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        MessagePrinter msp = MessagePrinter.getInstance(); 

        executor.submit(msp);

        msp.sendText(new String[] {"Welcome to the server, player!",
                "This server is about blablabla, this and that and a bit more of that and this",
                "Accept the tutorial?" });

        msp.sendText("More text to follow");

        // Shutdown:
        executor.shutdown();
        if (!executor.awaitTermination(2, TimeUnit.SECONDS)) {
            executor.shutdownNow();
        }
    }
}

答案 1 :(得分:0)

嗯,没有人回复。我自己解决了这个问题,但我并不为代码感到骄傲。不得不使用2个runnables ..
如果有人有兴趣,我会把代码保留在这里。

public void send(Player player,  long delay, String basecolor, String... strings) {
    List<String> str = Arrays.asList(strings);
    new BukkitRunnable() {
        int ind = 0;
        boolean next = true;
        @Override
        public void run() {
            String s = str.get(ind);
            if (next) {
                next = false;
                Bukkit.getScheduler().runTaskLater(YOUR_PLUGIN_INSTANCE, new Runnable() {
                    @Override
                    public void run() {
                            player.sendMessage(ChatColor.translateAlternateColorCodes('&',
                                    basecolor + s.replace("%p", player.getName()).replace("%s", server_name)));
                        next = true;
                    }
                }, (ind == 0 ? 0 : (str.get(ind - 1).length())));
                if (ind + 1 < str.size()) {
                    ind++;
                } else {
                    cancel();
                }
            }
        }
    }.runTaskTimer(YOUR_PLUGIN_INSTANCE, delay, 10);
}

这可以如下使用,作为一个例子:
send(player, 30, "&a", "Welcome to %s, %p!", "Enter the stuff you want to show here!", "They're all in the right order!");

答案 2 :(得分:0)

也许只是这样:

private void send(final Player player, String...messages) {

    long delaySum = 0;

    for (final String message : messages) {
        Runnable myTask = new Runnable() {
            public void run() {
                player.sendMessage(message);
            }
        };

        this.getServer().getScheduler().runTaskLater(this, myTask, delaySum);
        delaySum += message.length() * 2;
    }
}
通过这种方式,每条消息都会被之前计算的所有延迟所困扰。

注意:尚未经过测试