TimeUnit.SECONDS.sleep(1) 的备选方案; SpigotMC/SpigotMC 事件不是 运行

Alternatives for TimeUnit.SECONDS.sleep(1); SpigotMC/ SpigotMC event not running

我在尝试制作 Minecraft 插件时遇到了这个问题,但我认为这更像是一个 Java 讨论

所以我尝试制作一个每秒生成一只鸡的生成器(为了测试,当我完成时它会变为每分钟生成一次),但是在我测试时事件似乎没有 运行(因为 TimeUnit.SECONDS.sleep() 会阻塞 MC 线程)。那么我可以有其他选择吗? 我现在使用的延迟是 TimeUnit.SECONDS.sleep(*insert some number here*);
如下所示:

注意:我已经尝试使用 setTaskTimerscheduleSyncRepeatingTask 如答案所示,但它们似乎没有用。这是事件问题还是 spawnEntity 问题?

package com.TheRealBee.Bows.Event10;


import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;

import java.util.concurrent.TimeUnit;


public class EventManager10 implements Listener {
        @EventHandler

        public void onNukePlace(BlockPlaceEvent e){


            // Return if it's not TNT, doesn't have ItemMeta or doesn't have a custom dispaly name
            if(!e.getBlock().getType().equals(Material.GOLD_BLOCK) || !e.getItemInHand().hasItemMeta() || !e.getItemInHand().getItemMeta().hasDisplayName())
                return;
            // Return if the item display name is not correct
            if(!e.getItemInHand().getItemMeta().getDisplayName().equals(ChatColor.WHITE+"Spawner"))
                return;
            // Create the explosion
            try {
                for (int i = 0; i < 300000000; i++) {
                    e.getBlock().getLocation().getWorld().spawnEntity(e.getBlock().getLocation(), EntityType.CHICKEN);
                    TimeUnit.SECONDS.sleep(1);
                }
            }
            catch(InterruptedException ex)
            {
                Thread.currentThread().interrupt();
            }
            
        }
}

您应该使用 Bukkit.getScheduler().scheduleSyncRepeatingTask(...) 代替 for 循环和 TimeUnit.SECONDS.sleep

Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
    @Override
    public void run() {
        e.getBlock().getLocation().getWorld().spawnEntity(e.getBlock().getLocation(), EntityType.CHICKEN);
    }

}, 0L, 20L)

plugin 应该是你插件的实例

0L 是第一个任务 运行

之前的延迟(以滴答为单位)

20L 是下一个任务 运行

之前的延迟(以滴答为单位)

scheduleSyncRepeatingTask in the Spigot JavaDoc

因为这是一个生成器,所以我假设您希望在方块被破坏时停止生成小鸡。您可以使用任务 ID 取消任务。 taskID是scheduleSyncRepeatingTaskreturns的整数。您应该保存此 taskID,因为您可以稍后取消任务(当块中断时)。要取消任务,您可以使用 cancelTask:

Bukkit.getServer().getScheduler().cancelTask(taskID);

cancelTask in the Spigot JavaDoc

使用例如 HashMap 保存此 taskID。放置块后,您应该将坐标保存为键,将任务 ID 保存为 HashMap 中的值。当块被破坏时(使用 block break 事件),您应该在该 HashMap 中查找被破坏块的坐标。如果 HashMap 中存在坐标,则应取消任务并从 HashMap 中删除条目。

As , you could use a runnable. Bukkit has baked in methods 以利用此 Java 功能。这是首选,因为使用 Thread.sleep()TimeUnit.SECONDS.sleep() 包装)将暂停 Minecraft 所在的主线程 运行;调用将暂停所有内容(玩家移动、其他插件、世界生成等),如果时间延长,将导致客户端断开连接。

为了得到你想要的结果;重复操作,您应该使用 runTaskTimer 调度程序。有几种调用此调度程序的方法,但到目前为止最简单的方法如下:

Bukkit.getScheduler().runTaskTimer(plugin, () -> e.getBlock().getLocation().getWorld().spawnEntity(e.getBlock().getLocation(), EntityType.CHICKEN), 0L, 100L);

其中 plugin 是您的插件实例,() -> ...lambda expression to call the one action we want to execute, 0L is the delay to start the task (where L represents a long) 最后 100L 是 5 秒的滴答。每秒有 20 个滴答声,因此您可以执行 seconds * 20 以获得您想要的延迟滴答声(例如 60 * 20 = 1200L 1 分钟)。

当您希望鸡停止产卵时,

runTaskTimer 将 return BukkitTask that you can store and then later cancel 的一个实例。

有几种方法可以获取您的插件实例,但一种方法是在您从 main 调用它时简单地将实例传递给侦听器,例如:

Bukkit.getPluginManager().registerEvents(new EventManager10(this), this);

然后你会在 EventManager10:

中将默认的 constructor 换成你自己的

private final JavaPlugin plugin;

public EventManager10(JavaPlugin plugin){
    this.plugin = plugin;
}

总的来说,EventManager10不符合Java naming conventions,也许可以阅读这些,因为它对您的项目扩展有帮助。