Bukkit/Патрубок API - https://hub.spigotmc.org/javadocs/spigot/
Хорошо, что я пытаюсь сделать систему учебник для моего сервера. Я часто видел людей, отображающих текст следующим образом:Перебор текста с различной задержкой длины между нимиpublic void send(String...strings) { for (String string : strings) { player.sendMessage(string); } }
.., который ужасно. Как вы знаете, это рассылает чат и делает его нечитаемым.
Так что вместо этого я использую runnables для отображения текста с определенной задержкой. Я мог бы легко сделать runnable с той же определенной задержкой (т. Е. 30 тиков), но мне бы хотелось, чтобы runnable имел задержку, основанную на length() String.Я попытался сделать это следующим образом:
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
продолжается до следующей строки перед работоспособным проявившей текст.
Так что если у меня были эти предложения, например (в правильном порядке):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
Что я должен делать?
ответ
Ну, никто не ответил .. Закончился сам решить, но я не горжусь этим кодом. Пришлось использовать 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!");
Вы можете рассмотреть вопрос о проведении одного отдельного объекта (т.е. Singleton.), Который действует как принтер для печати всех сообщений. Это позволит избежать слишком большого количества потоков.
В приведенном ниже решении используется BlockingQueue, чтобы поток печати ожидал следующего сообщения. Когда сообщение не находится в очереди, метод run() будет ждать, не потребляя много CPU.
Решение поставляется в двух вариантах: - если вы раскомментируете первый msgQueue - вы получите блокирующее поведение sendMessage; метод будет ждать, пока все элементы будут напечатаны. - если вы не одобряете второй msgQueue - сообщения будут добавлены в очередь, не ожидая печати.
Я добавил ExecutorService для управления потоком, поскольку 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();
}
}
}
Может быть просто STH так:
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;
}
}
таким образом, каждое сообщение получает dalayed всех задержек, рассчитанные ранее.
Внимание: это еще не проверено