0

我在遇到这个问题时试图制作一个 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();
            }
            
        }
}

4

2 回答 2

1

如前所述,您可以使用可运行. Bukkit 已经加入了利用这个 Java 特性的方法。这是首选,因为 using (what wraps) 将暂停运行 Minecraft 的主线程;调用这将暂停一切(玩家移动、其他插件、世界生成等),并且如果延长会导致客户端断开连接。Thread.sleep()TimeUnit.SECONDS.sleep()

得到你想要的结果;一个重复的动作,你应该使用runTaskTimer调度器。有几种方法可以调用这个调度器,但到目前为止最简单的方法是这样的:

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

plugin你的插件的实例在哪里,() -> ...是一个lambda 表达式来调用我们想要执行的一个动作,0L是启动任务的延迟(其中L代表long),最后100L是 5 秒的滴答声。每秒有 20 个滴答声,因此您可以执行seconds * 20以获得延迟所需的滴答声(例如 60 * 20 = 1200L 1 分钟)。

runTaskTimer将返回一个您可以存储的实例,BukkitTask然后在您希望鸡停止产卵时取消。

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

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

然后你会换掉你自己的默认构造函数EventManager10


private final JavaPlugin plugin;

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

一般来说,EventManager10它不符合Java 命名约定,也许可以阅读这些,因为它会在您的项目扩展时帮助您。

于 2021-04-29T08:46:54.840 回答
1

您应该使用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是运行下一个任务之前的延迟(以刻度为单位)

Spigot JavaDoc 中的 scheduleSyncRepeatingTask

由于这是一个产卵器,我假设你会想要在方块被破坏时停止产卵。您可以使用其 taskID 取消任务。taskID 是scheduleSyncRepeatingTask返回的整数。您应该保存此任务 ID,因为您可以稍后取消任务(当块中断时)。要取消任务,您可以使用cancelTask

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

Spigot JavaDoc 中的 cancelTask

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

于 2021-04-29T07:35:16.400 回答