如何使用 getConfig() 在 Main class 之外的方法中编辑 config.yml

How to use getConfig() to edit config.yml in a method outside of the Main class

几天来我一直遇到路径问题,没有任何搜索可以帮助我克服。我最近才开始涉足 Bukkit 插件开发,这个简单的插件当前所做的就是设置 join/quit 消息和 AFK 状态。但是,后一部分给我带来了问题。

我的 Spigot 服务器控制台正在输出 无法将事件 PlayerJoinEvent 传递给 ServerBasics 当玩家加入时 未处理的异常在插件 ServerBasics 中执行命令 'afk' 当玩家输入 /afk 时。

逻辑:Mainclass的onEnable()为AfkCommand设置命令执行器,为JoinListener设置事件监听器,主要是监听玩家加入。此时,它应该在玩家加入时调用 ToggleAFK 中的 toggle() 方法,传递玩家的名字和一个 false 布尔值以在 config.yml 中为他们添加一个条目并确保他们而不是 afk,应该他们稍后键入 /afk 命令。然后 ToggleAFK 应使用 afk.[player] 等于 false.

保存配置

同时,AfkCommand 也应该调用ToggleAFK 并带有玩家名称和true/false 参数,ToggleAFK 应该以同样的方式处理。然而,它并没有这样做。

我已经通过代码设置了广播消息,以查看它何时失败。当玩家加入服务器时,JoinListener 广播 initjoined 但不会 toggled,AfkCommand 广播 abc 但不是 d,所以我们知道问题出在 ToggleAFK 中。 ToggleAFK 不广播 instancedg.

问题似乎出在我创建 Main class 的实例上,但我不知道如何在另一个 class 中启用 getConfig() 命令,它不会如果我所有的 config.yml 编辑都在 Main 中处理,那就太整洁了。我读过 Main class 不应该再次实例化,但我还找到了一个教程,其中以我在 ToggleAFK 中完成它的方式实例化了它,但我的不起作用(尽管它当我在 AfkCommand 中这样做时似乎很好。

我有哪些选择?是否有不同于其他 classes 的不同方式来编辑配置文件?我是否被迫在 Main 中编辑它们?问题是因为 ToggleAFK 在 Main 之后被称为两个 classes 而不是一个?感谢任何帮助。

我的主class:

package com.timothyreavis.serverbasics;

import org.bukkit.plugin.java.JavaPlugin;

public class Main extends JavaPlugin {

    @Override
    public void onEnable()
    {
        getCommand("afk").setExecutor(new AfkCommand(this));

        getServer().getPluginManager().registerEvents(new JoinListener(null), this);
    }

}

我的 JoinListener class(当玩家加入时将 afk 设置为 false。稍后我将对加入消息和内容进行软编码):

package com.timothyreavis.serverbasics;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;

import net.md_5.bungee.api.ChatColor;

public class JoinListener implements Listener
{
    // create ToggleAFK class instance
    ToggleAFK afk;
    public JoinListener(ToggleAFK instance) {
        afk = instance;
    }

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event)
    {
        Bukkit.broadcastMessage("init");
        // Player joins
        Player player = event.getPlayer();
        Bukkit.broadcastMessage("joined");
        afk.toggle(player, false);
        Bukkit.broadcastMessage("toggled");
        // set player entry as not afk in config.yml
        Bukkit.broadcastMessage("h");

        if (!player.hasPlayedBefore()) {
            // if player is new
            event.setJoinMessage(ChatColor.DARK_PURPLE + "Welcome " + ChatColor.GREEN + event.getPlayer().getName() + ChatColor.DARK_PURPLE + " to the server!");

            // tell player to read rules
            event.getPlayer().sendMessage(ChatColor.YELLOW + "Hi, " + player.getName() + "! " + Bukkit.getServerName() + " is a rather unique server with custom plugins, so please read our rules and commands before getting started.");
        } else {
            // if player isn't new
            event.setJoinMessage(ChatColor.GREEN + "[+] " + event.getPlayer().getName());
        }
    }
    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event)
    {
        // Player quits
        event.setQuitMessage(ChatColor.RED + "[-] " + event.getPlayer().getName());
    }
}

我的 ToggleAFK class(这应该在调用时编辑 config.yml 文件):

package com.timothyreavis.serverbasics;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import net.md_5.bungee.api.ChatColor;

public class ToggleAFK {
    // create Main class instance
    Main plugin;
    public ToggleAFK(Main instance) {
        plugin = instance;
        Bukkit.broadcastMessage("instanced");
    }

    public Boolean toggle(Player player, Boolean status) {
        Bukkit.broadcastMessage("g");
        plugin.getConfig().set("afk." + player, status);
        plugin.saveConfig();
        if (status) {
            Bukkit.broadcastMessage(ChatColor.DARK_PURPLE + player.getName() + " is now AFK.");
        } else {
            Bukkit.broadcastMessage(ChatColor.DARK_PURPLE + player.getName() + " is no longer AFK.");
        }
        return true;
    }
}

我的 AfkCommand class(处理 /afk 并调用 ToggleAFK):

package com.timothyreavis.serverbasics;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
//import org.bukkit.event.player.PlayerMoveEvent;

public class AfkCommand implements CommandExecutor {
    // create Main class instance
    Main plugin;
    public AfkCommand (Main instance) {
        plugin = instance;
    }
    // create ToggleAFK class instance
    ToggleAFK afk;
    public AfkCommand (ToggleAFK instance) {
        afk = instance;
    }

    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        Bukkit.broadcastMessage("a");
        if (sender instanceof Player) {
            Player player = (Player) sender;
            Bukkit.broadcastMessage("b");
            if (plugin.getConfig().getBoolean("afk."+sender) == false) {
                Bukkit.broadcastMessage("c");
                afk.toggle(player, true);
                Bukkit.broadcastMessage("d");
            } else {
                afk.toggle(player, false);
                Bukkit.broadcastMessage("d");
            }
        } else {
            Bukkit.broadcastMessage("e");
            return false;
        }
        // if command is used correctly, return true
        Bukkit.broadcastMessage("f");
        return true;
    }

}

据我所知,您的代码正确地将主插件 class 的引用传递给其他 classes 的构造函数,并且似乎没有创建您的新实例主插件class,所以那里应该没有障碍。当我测试你的代码时,无论是当玩家加入还是使用 /afk 命令时,都会抛出 NullPointerException,因为 AfkCommand 和 [=16= 中的 afk 字段] class 从未初始化。

由于您的 JoinListener class 在其构造函数中将 ToggleAFK 对象作为参数,而不是像您的代码当前那样使用 new JoinListener(null) 初始化它(这会产生NullPointerException 当到达行 afk.toggle(player, false) 时),我使用 new Listener(new ToggleAFK(this)).

将一个新的 ToggleAFK 对象传递给构造函数

您的 AfkCommand class 的替代构造函数似乎从未使用过,该构造函数将设置 afk 字段。您可以在这里初始化 afk 字段,方法是再次创建一个新的 ToggleAFK 对象,这次使用对主插件 class 的引用已经在 AfkCommand class 的其他构造函数中提供(你在 onEnable() 方法中使用的那个),像这样:

Main plugin;
ToggleAFK afk;
public AfkCommand (Main instance) {
    plugin = instance;
    afk = new ToggleAFK(plugin);
}

这些更改似乎使代码按照我测试时的预期运行。

需要注意两点:最好使用玩家的唯一 ID (player.getUniqueID()) 在配置文件中保存玩家的挂机状态,因为现在 set 方法正在调用 [= Player 对象上的 31=] 导致条目像这样开始:CraftPlayer{name=Steve}。这不仅看起来很奇怪,而且使用了玩家的名字,这可能会改变。此外,将 toggle 方法设为静态并将其放在 Util class 中可能更容易,这样您就不必创建 ToggleAFK 的所有实例class 访问该方法。这样的东西可能对你有用:

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;

public class Util {

    private static Main plugin;

    public static void initialize(Main instance) {
        plugin = instance;
    }

    public static void toggleAFK(Player player, boolean isAFK) {
        if (plugin == null) {
            throw new IllegalStateException("This class has not been initialized yet!");
        }
        plugin.getConfig().set("AFK." + player.getUniqueId(), isAFK);
        plugin.saveConfig();

        String message = ChatColor.DARK_PURPLE + player.getName();
        message += (isAFK) ? " is now AFK." : " is no longer AFK.";
        Bukkit.broadcastMessage(message);
    }

}

对于这个具体示例,您需要 "initialize" Util class,最好在您的 onEnable() 方法中使用 Util.initialize(this).