#java #loops #runnable #bukkit
#java #циклы #выполняемый #bukkit
Вопрос:
-
Bukkit / Spigot API — https://hub.spigotmc.org/javadocs/spigot /
Хорошо, я пытаюсь создать обучающую систему для моего сервера. Я часто видел, как люди отображали текст, подобный этому:public void send(String...strings) { for (String string : strings) { player.sendMessage(string); } }
.. что ужасно. Как вы знаете, это спамит чат и делает его нечитаемым.
Поэтому вместо этого я использую runnables для отображения текста с определенной задержкой. Я мог бы легко создать runnable с той же конкретной задержкой (т. Е. 30 тактов), но я бы хотел, чтобы у runnable была задержка, основанная на длине () строки.Я пытался сделать это следующим образом:
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
Что мне делать?
Ответ №1:
Возможно, вы захотите рассмотреть возможность использования одного объекта (т. Е. Singleton), который действует как принтер для печати всех сообщений. Это позволит избежать создания слишком большого количества потоков.
Приведенное ниже решение использует BlockingQueue для того, чтобы заставить поток печати ждать следующего сообщения. Когда сообщение не находится в очереди — метод run() будет ждать, не потребляя много ресурсов процессора.
Решение предлагается в двух вариантах: — если вы раскомментируете сначала msgQueue — вы получите блокирующее поведение SendMessage; метод будет ждать, пока все элементы не будут напечатаны. — если вы откомандируете второй msgQueue — сообщения будут добавлены в очередь без ожидания печати.
Я добавил ExecutorService для управления потоками, поскольку Oracle / Java считает это хорошей практикой для управления потоками с использованием ExecutorServices. Как только MessagePrinter не нужен — об этом сигнализирует «исполнитель.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();
}
}
}
Ответ №2:
Ну, никто не ответил.. В итоге решил это сам, но я не горжусь кодом. Пришлось использовать 2 исполняемых файла..
На случай, если кому-то интересно, я оставлю код здесь.
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('amp;',
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, "amp;a", "Welcome to %s, %p!", "Enter the stuff you want to show here!", "They're all in the right order!");
Ответ №3:
Может быть, просто что-то вроде этого:
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;
}
}
таким образом, каждое сообщение задерживается на все задержки, вычисленные ранее.
Внимание: Это не было протестировано