Я получаю сообщение об ошибке Plugin already initialized!
. Я уже знаю, что это означает, что я инициализирую свой основной класс дважды, и Bukkit/Spigot это не нравится.
Кажется, я не могу понять, где я это делаю или какая часть моего кода это делает. Я в порядке работы прочесал свой код по порядку: QLottery.java
, CommandManager.java
, Statistics.java
, а затем PlayerStats.java
. Насколько я могу судить, я использую только уже инициализированный экземпляр QLottery и не инициализирую другой.
Компилятор не выдает ошибок, и кажется, что это происходит только тогда, когда я запускаю команду /ql stats
. Все остальные команды работают без проблем.
Вот соответствующий код:
QLottery.java (основной класс):
package com.quietwind01;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import com.quietwind01.Listeners.CommandManager;
import com.quietwind01.Utils.EconomyUtils;
import com.quietwind01.YAML.PlayerStats;
public class QLottery extends JavaPlugin {
public ConcurrentHashMap<String, Integer> playerTickets;
public double totalPool;
public double poolDefaultAmount = getConfig().getDouble("pool-default-amount");
public int drawInterval = getConfig().getInt("draw-interval");
private final AtomicInteger interval;
ConcurrentHashMap<String, String> allTickets = new ConcurrentHashMap<>();
private int taskID = -1;
public String chatPrefix = "§5[§a§l§nQLottery§5]§f "; // Get plugin name for chat
private PlayerStats stats;
public QLottery() {
totalPool = poolDefaultAmount;
interval = new AtomicInteger(drawInterval);
}
@Override
public final void onEnable() {
try {
// Initialize hashmaps
playerTickets = new ConcurrentHashMap<>();
// Create the config file if it doesn't exist
saveDefaultConfig();
// Create the stats.yml file if it doesn't exist
saveStatsYAML();
// Send startup messages
startMessages(chatPrefix);
// Start DrawInterval timer
startMainTimer(interval);
// Register commands
getCommand("ql").setExecutor(new CommandManager(this));
} catch (Exception e) {
Bukkit.getServer().broadcastMessage(chatPrefix + "§cSomething went severely wrong. Please check logs. QLottery has been disabled.");
e.printStackTrace();
disablePlugin();
return;
}
}
}
CommandManager.java:
package com.quietwind01.Listeners;
import com.quietwind01.QLottery;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class CommandManager implements CommandExecutor {
private final QLottery plugin;
boolean debugMode = false;
public CommandManager(QLottery plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// Check args length
if (args.length == 0) {
sender.sendMessage(plugin.chatPrefix + "§cUsage: /ql <subcommand>");
return true;
}
// Get parent subcommand
String parentSubcommand = args[0].toLowerCase();
String childSubcommand = "";
if (args.length > 1) {
childSubcommand = args[1].toLowerCase();
}
if (debugMode == true) {
Player player = (Player) sender;
player.sendMessage(plugin.chatPrefix + "Parent subcommand: " + parentSubcommand);
player.sendMessage(plugin.chatPrefix + "Child subcommand: " + childSubcommand);
player.sendMessage(plugin.chatPrefix + "Args Length: " + args.length);
player.sendMessage(plugin.chatPrefix + "Is Ticket Command: " + "ticket".equals(parentSubcommand));
player.sendMessage(plugin.chatPrefix + "Is Pool Command: " + "pool".equals(parentSubcommand));
player.sendMessage(plugin.chatPrefix + "Is Stats Command: " + "stats".equals(parentSubcommand));
}
// Ticket subcommands
if ("ticket".equals(parentSubcommand)) {
switch (childSubcommand) {
case "buy":
return new TicketBuy(plugin).onCommand(sender, command, label, args);
case "sell":
return new TicketSell(plugin).onCommand(sender, command, label, args);
case "cost":
return new TicketCost(plugin).onCommand(sender, command, label, args);
default:
sender.sendMessage(plugin.chatPrefix + "§cUnknown subcommand. Usage: /ql <subcommand>");
}
}
// Tickets command
if ("tickets".equals(parentSubcommand)) {
return new TicketsOwned(plugin).onCommand(sender, command, label, args);
}
// Pool subcommands
if ("pool".equals(parentSubcommand)) {
return new TotalPool(plugin).onCommand(sender, command, label, args);
}
// Stats command
if ("stats".equals(parentSubcommand)) {
return new Statistics(plugin).onCommand(sender, command, label, args);
}
return true;
}
}
Статистика.java:
package com.quietwind01.Listeners;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.quietwind01.QLottery;
import com.quietwind01.YAML.PlayerStats;
public class Statistics implements CommandExecutor {
private final QLottery plugin;
private final PlayerStats stats;
public Statistics(QLottery plugin) {
this.plugin = plugin;
this.stats = new PlayerStats();
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(plugin.chatPrefix + "§cOnly players can use this command.");
return true;
}
Player player = (Player) sender;
// Check that player has proper permissions
if (!player.hasPermission("qlottery.stats")) {
player.sendMessage(plugin.chatPrefix + "§cYou do not have permission to use this command.");
return true;
}
// Debug
//player.sendMessage("TicketBuy Args: " + args.length);
// Check that the command has valid amount of arguments
if (args.length < 1) {
player.sendMessage(plugin.chatPrefix + "§eUsage: /ql stats");
return true;
}
// Check if the two arguments are "pool" and "amount"
if (!args[0].equalsIgnoreCase("stats")) {
player.sendMessage(plugin.chatPrefix + "§eUsage: /ql stats");
return true;
}
// Fetch the stats for the server
double serverTotalPayouts = stats.getServerPayoutTotal();
double serverTotalDraws = stats.getServerDrawsTotal();
double serverTotalWins = stats.getServerWinsTotal();
double lotteryTotalTickets = stats.getTotalTicketsPurchased("__LOTTERY__");
// Player stats
String playerName = player.getName();
stats.createNewPlayer(playerName); // Create the player in the stats file if they don't exist yet
double playerTotalWins = stats.getTotalWins(playerName);
double playerTotalPayout = stats.getTotalAmountWon(playerName);
double playerTotalTickets = stats.getTotalTicketsPurchased(playerName);
// Send the stats to the player
player.sendMessage(plugin.chatPrefix + "§3You have §6" + playerTotalWins + " §3wins, you've purchased §6" + playerTotalTickets + " §3tickets, and you've won a total of §a$" + playerTotalPayout + "§3!");
player.sendMessage(plugin.chatPrefix + "§3The server has drawn §6" + serverTotalDraws + " §3times, paid out §a$" + serverTotalPayouts + " §3and there have been a total of §6" + serverTotalWins + " §3jackpots won! There have been §6" + lotteryTotalTickets + " §3total tickets sold.");
return true;
}
}
PlayerStats.java:
package com.quietwind01.YAML;
import java.io.File;
import java.io.IOException;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
public class PlayerStats extends JavaPlugin {
private File file;
private YamlConfiguration config;
public PlayerStats() {
try {
// QLottery folder
File dir = getDataFolder();
// Create file object
this.file = new File(dir, "stats.yml");
// Get config
this.config = YamlConfiguration.loadConfiguration(file);
} catch (Exception e) {
Bukkit.broadcastMessage("§cCouldn't fetch stats.yml file.");
e.printStackTrace();
}
}
public boolean createNewPlayer(String playerName) {
try {
if (!config.contains("player-stats." + playerName)) {
config.set("player-stats." + playerName + ".total-wins", 0);
config.set("player-stats." + playerName + ".total-amount-won", 0);
config.set("player-stats." + playerName + ".total-tickets-purchased", 0);
config.save(file);
}
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't create new player (§b" + playerName + "§c).");
e.printStackTrace();
return false;
}
}
/*
* Server stats
*/
public double getServerPayoutTotal() {
return config.getDouble("player-stats.all-time-payout-total");
}
public double getServerDrawsTotal() {
return config.getDouble("player-stats.all-time-draws-total");
}
public double getServerWinsTotal() {
return config.getDouble("player-stats.all-time-wins");
}
public boolean updateServerPayoutTotal(double amountToAdd) {
try {
config.set("player-stats.all-time-payout-total", amountToAdd + getServerPayoutTotal());
config.save(file);
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't update total payout (server).");
e.printStackTrace();
return false;
}
}
public boolean updateServerDrawsTotal(double amountToAdd) {
try {
config.set("player-stats.all-time-draws-total", amountToAdd + getServerDrawsTotal());
config.save(file);
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't update total draws (server).");
e.printStackTrace();
return false;
}
}
public boolean updateServerWinsTotal(double amountToAdd) {
try {
config.set("player-stats.all-time-wins", amountToAdd + getServerWinsTotal());
config.save(file);
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't update total wins (server).");
e.printStackTrace();
return false;
}
}
/*
* Player stats
*/
public double getTotalWins(String playerName) {
return config.getDouble("player-stats." + playerName + ".total-wins");
}
public double getTotalAmountWon(String playerName) {
return config.getDouble("player-stats." + playerName + ".total-amount-won");
}
public double getTotalTicketsPurchased(String playerName) {
return config.getDouble("player-stats." + playerName + ".total-tickets-purchased");
}
public boolean updateTotalWins(String playerName, double amountToAdd) {
try {
config.set("player-stats." + playerName + ".total-wins", amountToAdd + getTotalWins(playerName));
config.save(file);
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't update total wins. (Player)");
e.printStackTrace();
return false;
}
}
public boolean updateTotalAmountWon(String playerName, double amountToAdd) {
try {
config.set("player-stats." + playerName + ".total-amount-won", amountToAdd + getTotalAmountWon(playerName));
config.save(file);
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't update total amount won (player).");
e.printStackTrace();
return false;
}
}
public boolean updateTotalTicketsPurchased(String playerName, double amountToAdd) {
try {
config.set("player-stats." + playerName + ".total-tickets-purchased", amountToAdd + getTotalTicketsPurchased(playerName));
config.save(file);
return true;
} catch (IOException e) {
Bukkit.broadcastMessage("§cCouldn't update total tickets purchased (player).");
e.printStackTrace();
return false;
}
}
}
Вот трассировка стека консоли:
org.bukkit.command.CommandException: Unhandled exception executing command 'ql' in plugin Qlottery v1.0.0-RC.3
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:47) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:149) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_20_R3.CraftServer.dispatchCommand(CraftServer.java:887) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at org.bukkit.craftbukkit.v1_20_R3.command.BukkitCommandWrapper.run(BukkitCommandWrapper.java:50) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at com.mojang.brigadier.context.ContextChain.runExecutable(ContextChain.java:73) ~[brigadier-1.2.9.jar:?]
at net.minecraft.commands.execution.tasks.ExecuteCommand.a(SourceFile:29) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.execution.tasks.ExecuteCommand.execute(SourceFile:13) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.execution.UnboundEntryAction.a(SourceFile:8) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.execution.CommandQueueEntry.a(SourceFile:8) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.execution.ExecutionContext.a(SourceFile:107) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.CommandDispatcher.a(CommandDispatcher.java:413) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.CommandDispatcher.performCommand(CommandDispatcher.java:335) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.commands.CommandDispatcher.a(CommandDispatcher.java:322) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1856) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.network.PlayerConnection.lambda$15(PlayerConnection.java:1818) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.util.thread.IAsyncTaskHandler.b(SourceFile:67) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768) ~[?:?]
at net.minecraft.server.TickTask.run(SourceFile:18) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.util.thread.IAsyncTaskHandler.d(SourceFile:156) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.util.thread.IAsyncTaskHandlerReentrant.d(SourceFile:23) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1191) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.d(MinecraftServer.java:1) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.util.thread.IAsyncTaskHandler.x(SourceFile:130) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.bl(MinecraftServer.java:1170) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.x(MinecraftServer.java:1163) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.util.thread.IAsyncTaskHandler.c(SourceFile:139) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.w_(MinecraftServer.java:1147) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:1060) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:304) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at java.lang.Thread.run(Thread.java:1570) ~[?:?]
Caused by: java.lang.IllegalArgumentException: Plugin already initialized!
at org.bukkit.plugin.java.PluginClassLoader.initialize(PluginClassLoader.java:238) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.JavaPlugin.<init>(JavaPlugin.java:55) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at com.quietwind01.YAML.PlayerStats.<init>(PlayerStats.java:16) ~[?:?]
at com.quietwind01.Listeners.Statistics.<init>(Statistics.java:14) ~[?:?]
at com.quietwind01.Listeners.CommandManager.onCommand(CommandManager.java:74) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
... 29 more
Caused by: java.lang.IllegalStateException: Initial initialization
at org.bukkit.plugin.java.PluginClassLoader.initialize(PluginClassLoader.java:241) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.JavaPlugin.<init>(JavaPlugin.java:55) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at com.quietwind01.QLottery.<init>(QLottery.java:33) ~[?:?]
at jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[?:?]
at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502) ~[?:?]
at java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?]
at org.bukkit.plugin.java.PluginClassLoader.<init>(PluginClassLoader.java:88) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:145) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.java:405) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:312) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:121) ~[spigot-api-1.20.4-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_20_R3.CraftServer.loadPlugins(CraftServer.java:430) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.dedicated.DedicatedServer.e(DedicatedServer.java:223) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:1000) ~[spigot-1.20.4-R0.1-SNAPSHOT.jar:4090-Spigot-b754dcc-38b1f49]
... 2 more
Какая часть приведенного выше кода может вызвать это? Насколько я могу судить, я не инициализирую QLottery
дважды...
Обновлено: НЕТ, я не могу этого сделать, я тупой, лол.
Да, расширение QLottery
по-прежнему делает его подклассом JavaPlugin
. Вам нужно просто передать то, что PlayerStats
нужно, через его конструктор. Или передайте весь экземпляр QLottery
через конструктор.
Передать QLottery
было бы проще, и в итоге я именно это и сделал, потому что QLottery
уже передан в класс CommandManager
, который управляет PlayerStats
, TicketBuy
и TicketSale
. Черт возьми, честно говоря, я чувствую себя таким глупым, лол. Я немного новичок в Java, но я также знаю множество других языков, поэтому иногда путаю себя, лол.
Загрузчик плагинов загружает ваш плагин, создавая экземпляр QLottery
, который вызывает конструктор JavaPlugin
, который инициализирует ваш плагин.
Затем вы создаете экземпляр PlayerStats
в Statistics
:
public Statistics(QLottery plugin) {
this.plugin = plugin;
this.stats = new PlayerStats(); // here!
}
Это приводит к повторному вызову конструктора JavaPlugin
, и в этом загрузчик классов плагина обнаруживает, что ваш плагин уже инициализирован, и выдает полученное вами исключение.
У вас не должно быть нескольких подклассов JavaPlugin
в одном плагине. Кажется, PlayerStats
должно быть просто обычным занятием. Возьмите каталог папки данных в качестве параметра конструктора.
public class PlayerStats {
private File file;
private YamlConfiguration config;
public PlayerStats(File dataDir) {
try {
this.file = new File(dataDir, "stats.yml");
// ...
и передайте параметр следующим образом:
public Statistics(QLottery plugin) {
this.plugin = plugin;
this.stats = new PlayerStats(plugin.getDataFolder());
}
Если вам нужно использовать другие методы из JavaPlugin
, рассмотрите возможность передачи всего экземпляра QLottery
так же, как вы передали его в Statistics
.
Если вы действительно хотите создать несколько плагинов, у вас должно быть несколько файлов plugin.yml, идентифицирующих каждый из них, и они должны выводиться как отдельные jar-файлы.
Это определенно было оно, спасибо
@Sweeper
getFolderData()
не будет работать безJavaPlugin
класса... опять же, вместо этого я мог бы расширить QLottery и получить тот же результат, я удивлен, что пропустил это.