Refactor CoreProtect.java

This commit is contained in:
Intelli 2025-02-26 14:05:32 -07:00
parent 779b1acbff
commit 1d294c51c4
4 changed files with 371 additions and 185 deletions

View file

@ -1,37 +1,18 @@
package net.coreprotect;
import java.io.File;
import java.util.Iterator;
import java.util.Map.Entry;
import org.bstats.bukkit.MetricsLite;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import net.coreprotect.command.CommandHandler;
import net.coreprotect.command.TabHandler;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.language.Language;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.ListenerHandler;
import net.coreprotect.listener.player.PlayerQuitListener;
import net.coreprotect.paper.PaperAdapter;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.thread.NetworkHandler;
import net.coreprotect.thread.Scheduler;
import net.coreprotect.services.PluginInitializationService;
import net.coreprotect.services.ShutdownService;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatUtils;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.Teleport;
import net.coreprotect.utility.VersionUtils;
/**
* Main class for the CoreProtect plugin
*/
public final class CoreProtect extends JavaPlugin {
private static CoreProtect instance;
@ -45,7 +26,7 @@ public final class CoreProtect extends JavaPlugin {
return instance;
}
private CoreProtectAPI api = new CoreProtectAPI();
private final CoreProtectAPI api = new CoreProtectAPI();
/**
* Get the CoreProtect API
@ -58,73 +39,15 @@ public final class CoreProtect extends JavaPlugin {
@Override
public void onEnable() {
// Set plugin instance and data folder path
instance = this;
ConfigHandler.path = this.getDataFolder().getPath() + File.separator;
Language.loadPhrases();
boolean start = performVersionChecks();
if (start) {
try {
Consumer.initialize(); // Prepare consumer (keep this here)
new ListenerHandler(this);
getCommand("coreprotect").setExecutor(CommandHandler.getInstance());
getCommand("coreprotect").setTabCompleter(new TabHandler());
getCommand("core").setExecutor(CommandHandler.getInstance());
getCommand("core").setTabCompleter(new TabHandler());
getCommand("co").setExecutor(CommandHandler.getInstance());
getCommand("co").setTabCompleter(new TabHandler());
// Initialize plugin using the initialization service
boolean initialized = PluginInitializationService.initializePlugin(this);
boolean exists = (new File(ConfigHandler.path)).exists();
if (!exists) {
new File(ConfigHandler.path).mkdir();
}
start = ConfigHandler.performInitialization(true); // Perform any necessary initialization
}
catch (Exception e) {
e.printStackTrace();
start = false;
}
}
if (start) {
PluginDescriptionFile pluginDescription = this.getDescription();
ChatUtils.sendConsoleComponentStartup(Bukkit.getServer().getConsoleSender(), Phrase.build(Phrase.ENABLE_SUCCESS, ConfigHandler.EDITION_NAME));
if (Config.getGlobal().MYSQL) {
Chat.console(Phrase.build(Phrase.USING_MYSQL));
}
else {
Chat.console(Phrase.build(Phrase.USING_SQLITE));
}
Chat.console("--------------------");
Chat.console(Phrase.build(Phrase.ENJOY_COREPROTECT, pluginDescription.getName()));
Chat.console(Phrase.build(Phrase.LINK_DISCORD, "www.coreprotect.net/discord/"));
Chat.console("--------------------");
Scheduler.scheduleSyncDelayedTask(this, () -> {
try {
Thread networkHandler = new Thread(new NetworkHandler(true, true));
networkHandler.start();
}
catch (Exception e) {
e.printStackTrace();
}
}, 0);
Thread cacheCleanUpThread = new Thread(new CacheHandler());
cacheCleanUpThread.start();
Consumer.startConsumer();
// Enabling bStats
try {
new MetricsLite(this, 2876);
}
catch (Exception e) {
// Failed to connect to bStats server or something else went wrong.
}
}
else {
// Disable plugin if initialization failed
if (!initialized) {
Chat.console(Phrase.build(Phrase.ENABLE_FAILED, ConfigHandler.EDITION_NAME));
getServer().getPluginManager().disablePlugin(this);
}
@ -132,102 +55,6 @@ public final class CoreProtect extends JavaPlugin {
@Override
public void onDisable() {
safeShutdown(this);
ShutdownService.safeShutdown(this);
}
private static boolean performVersionChecks() {
try {
String[] bukkitVersion = Bukkit.getServer().getBukkitVersion().split("[-.]");
if (VersionUtils.newVersion(bukkitVersion[0] + "." + bukkitVersion[1], ConfigHandler.MINECRAFT_VERSION)) {
Chat.console(Phrase.build(Phrase.VERSION_REQUIRED, "Minecraft", ConfigHandler.MINECRAFT_VERSION));
return false;
}
if (VersionUtils.newVersion(ConfigHandler.LATEST_VERSION, bukkitVersion[0] + "." + bukkitVersion[1]) && VersionUtils.isBranch("master")) {
Chat.console(Phrase.build(Phrase.VERSION_INCOMPATIBLE, "Minecraft", bukkitVersion[0] + "." + bukkitVersion[1]));
return false;
}
String[] javaVersion = (System.getProperty("java.version").replaceAll("[^0-9.]", "") + ".0").split("\\.");
if (VersionUtils.newVersion(javaVersion[0] + "." + javaVersion[1], ConfigHandler.JAVA_VERSION)) {
Chat.console(Phrase.build(Phrase.VERSION_REQUIRED, "Java", ConfigHandler.JAVA_VERSION));
return false;
}
if (ConfigHandler.EDITION_BRANCH.length() == 0) {
Chat.sendConsoleMessage(Color.RED + "[CoreProtect] " + Phrase.build(Phrase.INVALID_BRANCH_1));
Chat.sendConsoleMessage(Color.GREY + "[CoreProtect] " + Phrase.build(Phrase.INVALID_BRANCH_2));
Chat.sendConsoleMessage(Color.GREY + "[CoreProtect] " + Phrase.build(Phrase.INVALID_BRANCH_3));
return false;
}
ConfigHandler.SERVER_VERSION = Integer.parseInt(bukkitVersion[1]);
}
catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private static void safeShutdown(CoreProtect plugin) {
try {
/* if server is stopping, log disconnections of online players */
if (ConfigHandler.serverRunning && PaperAdapter.ADAPTER.isStopping(plugin.getServer())) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
PlayerQuitListener.queuePlayerQuit(player);
}
}
if (!ConfigHandler.isFolia) {
Iterator<Entry<Location, BlockData>> iterator = Teleport.revertBlocks.entrySet().iterator();
while (iterator.hasNext()) {
Entry<Location, BlockData> entry = iterator.next();
entry.getKey().getBlock().setBlockData(entry.getValue());
iterator.remove();
}
}
ConfigHandler.serverRunning = false;
long shutdownTime = System.currentTimeMillis();
long alertTime = shutdownTime + (10 * 1000);
if (ConfigHandler.converterRunning) {
Chat.console(Phrase.build(Phrase.FINISHING_CONVERSION));
}
else {
Chat.console(Phrase.build(Phrase.FINISHING_LOGGING));
}
if (ConfigHandler.migrationRunning) {
ConfigHandler.purgeRunning = false;
}
while ((Consumer.isRunning() || ConfigHandler.converterRunning) && !ConfigHandler.purgeRunning) {
long time = System.currentTimeMillis();
if (time >= alertTime) {
if (!ConfigHandler.converterRunning) {
int consumerId = (Consumer.currentConsumer == 1) ? 1 : 0;
int consumerCount = Consumer.getConsumerSize(consumerId) + Process.getCurrentConsumerSize();
Chat.console(Phrase.build(Phrase.LOGGING_ITEMS, String.format("%,d", consumerCount)));
}
alertTime = alertTime + (30 * 1000);
}
else if (!ConfigHandler.databaseReachable && (time - shutdownTime) >= (5 * 60 * 1000)) {
Chat.console(Phrase.build(Phrase.DATABASE_UNREACHABLE));
break;
}
else if ((time - shutdownTime) >= (15 * 60 * 1000)) {
Chat.console(Phrase.build(Phrase.LOGGING_TIME_LIMIT));
break;
}
Thread.sleep(100);
}
ConfigHandler.performDisable();
Chat.console(Phrase.build(Phrase.DISABLE_SUCCESS, "CoreProtect v" + plugin.getDescription().getVersion()));
}
catch (Exception e) {
e.printStackTrace();
}
}
}

View file

@ -0,0 +1,172 @@
package net.coreprotect.services;
import java.io.File;
import org.bstats.bukkit.MetricsLite;
import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import net.coreprotect.CoreProtect;
import net.coreprotect.command.CommandHandler;
import net.coreprotect.command.TabHandler;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.language.Language;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.ListenerHandler;
import net.coreprotect.thread.CacheHandler;
import net.coreprotect.thread.NetworkHandler;
import net.coreprotect.thread.Scheduler;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.ChatUtils;
/**
* Service responsible for plugin initialization tasks
*/
public class PluginInitializationService {
private PluginInitializationService() {
throw new IllegalStateException("Utility class");
}
/**
* Initializes plugin components and configurations
*
* @param plugin
* The CoreProtect plugin instance
* @return true if initialization was successful, false otherwise
*/
public static boolean initializePlugin(CoreProtect plugin) {
// Load language phrases
Language.loadPhrases();
// Perform version checks
boolean start = VersionCheckService.performVersionChecks();
if (!start) {
return false;
}
try {
// Initialize core components
Consumer.initialize();
new ListenerHandler(plugin);
// Register commands
registerCommands(plugin);
// Ensure data directory exists
createDataDirectory();
// Initialize configuration
start = ConfigHandler.performInitialization(true);
}
catch (Exception e) {
e.printStackTrace();
return false;
}
if (start) {
// Display startup messages
displayStartupMessages(plugin);
// Start background services
startBackgroundServices(plugin);
// Start metrics
enableMetrics(plugin);
}
return start;
}
/**
* Registers plugin commands
*
* @param plugin
* The CoreProtect plugin instance
*/
private static void registerCommands(JavaPlugin plugin) {
plugin.getCommand("coreprotect").setExecutor(CommandHandler.getInstance());
plugin.getCommand("coreprotect").setTabCompleter(new TabHandler());
plugin.getCommand("core").setExecutor(CommandHandler.getInstance());
plugin.getCommand("core").setTabCompleter(new TabHandler());
plugin.getCommand("co").setExecutor(CommandHandler.getInstance());
plugin.getCommand("co").setTabCompleter(new TabHandler());
}
/**
* Creates the plugin data directory if it doesn't exist
*/
private static void createDataDirectory() {
boolean exists = (new File(ConfigHandler.path)).exists();
if (!exists) {
new File(ConfigHandler.path).mkdir();
}
}
/**
* Displays startup messages in the console
*
* @param plugin
* The CoreProtect plugin instance
*/
private static void displayStartupMessages(JavaPlugin plugin) {
PluginDescriptionFile pluginDescription = plugin.getDescription();
ChatUtils.sendConsoleComponentStartup(Bukkit.getServer().getConsoleSender(), Phrase.build(Phrase.ENABLE_SUCCESS, ConfigHandler.EDITION_NAME));
if (Config.getGlobal().MYSQL) {
Chat.console(Phrase.build(Phrase.USING_MYSQL));
}
else {
Chat.console(Phrase.build(Phrase.USING_SQLITE));
}
Chat.console("--------------------");
Chat.console(Phrase.build(Phrase.ENJOY_COREPROTECT, pluginDescription.getName()));
Chat.console(Phrase.build(Phrase.LINK_DISCORD, "www.coreprotect.net/discord/"));
Chat.console("--------------------");
}
/**
* Starts background services
*
* @param plugin
* The CoreProtect plugin instance
*/
private static void startBackgroundServices(CoreProtect plugin) {
// Start network handler
Scheduler.scheduleSyncDelayedTask(plugin, () -> {
try {
Thread networkHandler = new Thread(new NetworkHandler(true, true));
networkHandler.start();
}
catch (Exception e) {
e.printStackTrace();
}
}, 0);
// Start cache cleanup thread
Thread cacheCleanUpThread = new Thread(new CacheHandler());
cacheCleanUpThread.start();
// Start consumer
Consumer.startConsumer();
}
/**
* Enables metrics reporting
*
* @param plugin
* The CoreProtect plugin instance
*/
private static void enableMetrics(JavaPlugin plugin) {
try {
new MetricsLite(plugin, 2876);
}
catch (Exception e) {
// Failed to connect to bStats server or something else went wrong
}
}
}

View file

@ -0,0 +1,122 @@
package net.coreprotect.services;
import java.util.Iterator;
import java.util.Map.Entry;
import org.bukkit.Location;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.consumer.process.Process;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.player.PlayerQuitListener;
import net.coreprotect.paper.PaperAdapter;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Teleport;
/**
* Service responsible for handling plugin shutdown operations
*/
public class ShutdownService {
private static final long ALERT_INTERVAL_MS = 30 * 1000; // 30 seconds
private static final long MAX_SHUTDOWN_WAIT_MS = 15 * 60 * 1000; // 15 minutes
private static final long DB_UNREACHABLE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
private ShutdownService() {
throw new IllegalStateException("Utility class");
}
/**
* Safely shuts down the plugin, ensuring all data is saved
*
* @param plugin
* The CoreProtect plugin instance
*/
public static void safeShutdown(Plugin plugin) {
try {
// Log disconnections of online players if server is stopping
if (ConfigHandler.serverRunning && PaperAdapter.ADAPTER.isStopping(plugin.getServer())) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
PlayerQuitListener.queuePlayerQuit(player);
}
}
// Revert any teleport blocks if not using Folia
if (!ConfigHandler.isFolia) {
revertTeleportBlocks();
}
ConfigHandler.serverRunning = false;
long shutdownTime = System.currentTimeMillis();
long nextAlertTime = shutdownTime + ALERT_INTERVAL_MS;
if (ConfigHandler.converterRunning) {
Chat.console(Phrase.build(Phrase.FINISHING_CONVERSION));
}
else {
Chat.console(Phrase.build(Phrase.FINISHING_LOGGING));
}
if (ConfigHandler.migrationRunning) {
ConfigHandler.purgeRunning = false;
}
waitForPendingOperations(shutdownTime, nextAlertTime);
ConfigHandler.performDisable();
Chat.console(Phrase.build(Phrase.DISABLE_SUCCESS, "CoreProtect v" + plugin.getDescription().getVersion()));
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* Waits for pending operations (consumer tasks or conversions) to complete
*
* @param shutdownTime
* The time when shutdown began
* @param nextAlertTime
* The time for the next status message
*/
private static void waitForPendingOperations(long shutdownTime, long nextAlertTime) throws InterruptedException {
while ((Consumer.isRunning() || ConfigHandler.converterRunning) && !ConfigHandler.purgeRunning) {
long currentTime = System.currentTimeMillis();
if (currentTime >= nextAlertTime) {
if (!ConfigHandler.converterRunning) {
int consumerId = (Consumer.currentConsumer == 1) ? 1 : 0;
int consumerCount = Consumer.getConsumerSize(consumerId) + Process.getCurrentConsumerSize();
Chat.console(Phrase.build(Phrase.LOGGING_ITEMS, String.format("%,d", consumerCount)));
}
nextAlertTime = currentTime + ALERT_INTERVAL_MS;
}
else if (!ConfigHandler.databaseReachable && (currentTime - shutdownTime) >= DB_UNREACHABLE_TIMEOUT_MS) {
Chat.console(Phrase.build(Phrase.DATABASE_UNREACHABLE));
break;
}
else if ((currentTime - shutdownTime) >= MAX_SHUTDOWN_WAIT_MS) {
Chat.console(Phrase.build(Phrase.LOGGING_TIME_LIMIT));
break;
}
Thread.sleep(100);
}
}
/**
* Reverts any blocks that were temporarily changed during player teleports
*/
private static void revertTeleportBlocks() {
Iterator<Entry<Location, BlockData>> iterator = Teleport.revertBlocks.entrySet().iterator();
while (iterator.hasNext()) {
Entry<Location, BlockData> entry = iterator.next();
entry.getKey().getBlock().setBlockData(entry.getValue());
iterator.remove();
}
}
}

View file

@ -0,0 +1,65 @@
package net.coreprotect.services;
import org.bukkit.Bukkit;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.language.Phrase;
import net.coreprotect.utility.Chat;
import net.coreprotect.utility.Color;
import net.coreprotect.utility.VersionUtils;
/**
* Service responsible for checking compatibility of Minecraft, Java versions,
* and plugin branch validation.
*/
public class VersionCheckService {
private VersionCheckService() {
throw new IllegalStateException("Utility class");
}
/**
* Performs all necessary version checks during plugin startup
*
* @return true if all version checks pass, false otherwise
*/
public static boolean performVersionChecks() {
try {
// Check Minecraft version compatibility
String[] bukkitVersion = Bukkit.getServer().getBukkitVersion().split("[-.]");
if (VersionUtils.newVersion(bukkitVersion[0] + "." + bukkitVersion[1], ConfigHandler.MINECRAFT_VERSION)) {
Chat.console(Phrase.build(Phrase.VERSION_REQUIRED, "Minecraft", ConfigHandler.MINECRAFT_VERSION));
return false;
}
if (VersionUtils.newVersion(ConfigHandler.LATEST_VERSION, bukkitVersion[0] + "." + bukkitVersion[1]) && VersionUtils.isBranch("master")) {
Chat.console(Phrase.build(Phrase.VERSION_INCOMPATIBLE, "Minecraft", bukkitVersion[0] + "." + bukkitVersion[1]));
return false;
}
// Check Java version compatibility
String[] javaVersion = (System.getProperty("java.version").replaceAll("[^0-9.]", "") + ".0").split("\\.");
if (VersionUtils.newVersion(javaVersion[0] + "." + javaVersion[1], ConfigHandler.JAVA_VERSION)) {
Chat.console(Phrase.build(Phrase.VERSION_REQUIRED, "Java", ConfigHandler.JAVA_VERSION));
return false;
}
// Branch validation
if (ConfigHandler.EDITION_BRANCH.length() == 0) {
Chat.sendConsoleMessage(Color.RED + "[CoreProtect] " + Phrase.build(Phrase.INVALID_BRANCH_1));
Chat.sendConsoleMessage(Color.GREY + "[CoreProtect] " + Phrase.build(Phrase.INVALID_BRANCH_2));
Chat.sendConsoleMessage(Color.GREY + "[CoreProtect] " + Phrase.build(Phrase.INVALID_BRANCH_3));
return false;
}
// Store Minecraft server version for later use
ConfigHandler.SERVER_VERSION = Integer.parseInt(bukkitVersion[1]);
}
catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}