diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..4561ce1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + + com.user404_ + BalSync + 0.1-alpha + jar + + BalSync + + + 21 + UTF-8 + + + + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + + + + + + src/main/resources + true + + + + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + + jitpack.io + https://jitpack.io + + + + + + io.papermc.paper + paper-api + 1.21-R0.1-SNAPSHOT + provided + + + + com.github.MilkBowl + VaultAPI + 1.7 + provided + + + + mysql + mysql-connector-java + 8.0.33 + + + + com.zaxxer + HikariCP + 5.0.1 + + + diff --git a/src/main/java/com/user404_/balsync/BalSyncCommand.java b/src/main/java/com/user404_/balsync/BalSyncCommand.java new file mode 100644 index 0000000..017053e --- /dev/null +++ b/src/main/java/com/user404_/balsync/BalSyncCommand.java @@ -0,0 +1,56 @@ +package com.user404_.balsync; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class BalSyncCommand implements CommandExecutor { + private final BalSyncPlugin plugin; + private final BalanceManager balanceManager; + + public BalSyncCommand(BalSyncPlugin plugin, BalanceManager balanceManager) { + this.plugin = plugin; + this.balanceManager = balanceManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!sender.hasPermission("balsync.admin")) { + sender.sendMessage(plugin.getTranslationManager().formatMessage("no-permission")); + return true; + } + + if (args.length == 0) { + sender.sendMessage(plugin.getTranslationManager().formatMessage("usage")); + return true; + } + + switch (args[0].toLowerCase()) { + case "reload": + plugin.getConfigManager().reload(); + plugin.getTranslationManager().loadMessages(); + sender.sendMessage(plugin.getTranslationManager().formatMessage("config-reloaded")); + break; + + case "save": + balanceManager.saveAllBalances(); + sender.sendMessage(plugin.getTranslationManager().formatMessage("balance-saved")); + break; + + case "load": + if (sender instanceof Player) { + balanceManager.loadPlayerBalance((Player) sender); + } else { + sender.sendMessage(plugin.getTranslationManager().formatMessage("player-not-found")); + } + break; + + default: + sender.sendMessage(plugin.getTranslationManager().formatMessage("usage")); + break; + } + + return true; + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/balsync/BalSyncPlugin.java b/src/main/java/com/user404_/balsync/BalSyncPlugin.java new file mode 100644 index 0000000..5557e83 --- /dev/null +++ b/src/main/java/com/user404_/balsync/BalSyncPlugin.java @@ -0,0 +1,122 @@ +package com.user404_.balsync; + +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import net.milkbowl.vault.economy.Economy; +import java.util.logging.Logger; + +public class BalSyncPlugin extends JavaPlugin { + private static BalSyncPlugin instance; + private Economy economy; + private DatabaseManager databaseManager; + private BalanceManager balanceManager; + private TranslationManager translationManager; + private ConfigManager configManager; + private Logger logger; + + @Override + public void onEnable() { + instance = this; + logger = getLogger(); + + // Load configuration + configManager = new ConfigManager(this); + configManager.loadConfig(); + + // Load translations + translationManager = new TranslationManager(this); + translationManager.loadMessages(); + + // Setup Vault economy + if (!setupEconomy()) { + logger.severe("Vault economy not found! Disabling plugin..."); + getServer().getPluginManager().disablePlugin(this); + return; + } + + // Initialize database + databaseManager = new DatabaseManager(this); + if (!databaseManager.connect()) { + logger.severe("Failed to connect to database! Disabling plugin..."); + getServer().getPluginManager().disablePlugin(this); + return; + } + + // Setup database tables + databaseManager.setupTables(); + + // Initialize balance manager + balanceManager = new BalanceManager(this, economy, databaseManager); + + // Register event listeners + getServer().getPluginManager().registerEvents(new PlayerEventListener(this, balanceManager), this); + + // Register commands + getCommand("balsync").setExecutor(new BalSyncCommand(this, balanceManager)); + + // Start auto-save task if enabled + int interval = configManager.getAutoSaveInterval(); + if (interval > 0) { + getServer().getScheduler().runTaskTimerAsynchronously(this, + () -> balanceManager.saveAllBalances(), + interval * 20L, interval * 20L); + } + + logger.info("BalSync v" + getDescription().getVersion() + " enabled successfully!"); + } + + @Override + public void onDisable() { + // Save all balances on shutdown + if (balanceManager != null) { + balanceManager.saveAllBalances(); + } + + // Close database connection + if (databaseManager != null) { + databaseManager.disconnect(); + } + + logger.info("BalSync disabled."); + } + + private boolean setupEconomy() { + if (getServer().getPluginManager().getPlugin("Vault") == null) { + return false; + } + + RegisteredServiceProvider rsp = getServer().getServicesManager() + .getRegistration(Economy.class); + if (rsp == null) { + return false; + } + + economy = rsp.getProvider(); + return economy != null; + } + + public static BalSyncPlugin getInstance() { + return instance; + } + + public Economy getEconomy() { + return economy; + } + + public DatabaseManager getDatabaseManager() { + return databaseManager; + } + + public TranslationManager getTranslationManager() { + return translationManager; + } + + public ConfigManager getConfigManager() { + return configManager; + } + + public Logger getPluginLogger() { + return logger; + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/balsync/BalanceManager.java b/src/main/java/com/user404_/balsync/BalanceManager.java new file mode 100644 index 0000000..82a94b6 --- /dev/null +++ b/src/main/java/com/user404_/balsync/BalanceManager.java @@ -0,0 +1,107 @@ +package com.user404_.balsync; + +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import java.sql.SQLException; +import java.util.UUID; +import java.util.logging.Level; + +public class BalanceManager { + private final BalSyncPlugin plugin; + private final Economy economy; + private final DatabaseManager databaseManager; + + public BalanceManager(BalSyncPlugin plugin, Economy economy, DatabaseManager databaseManager) { + this.plugin = plugin; + this.economy = economy; + this.databaseManager = databaseManager; + } + + public void loadPlayerBalance(Player player) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + try { + double databaseBalance = databaseManager.getBalance(player.getUniqueId()); + + Bukkit.getScheduler().runTask(plugin, () -> { + // Sicherstellen, dass der Spieler ein Konto hat + if (!economy.hasAccount(player)) { + economy.createPlayerAccount(player); + } + + // Aktuelle Balance abrufen + double currentBalance = economy.getBalance(player); + + // KOMPLETTE ÜBERSCHREIBUNG der Balance + // 1. Zuerst auf 0 setzen (alles abheben oder auf 0 bringen) + if (currentBalance > 0) { + // Positive Balance abheben + economy.withdrawPlayer(player, currentBalance); + } else if (currentBalance < 0) { + // Negative Balance ausgleichen (einzahlen um auf 0 zu kommen) + economy.depositPlayer(player, Math.abs(currentBalance)); + } + + // 2. Datenbankbalance einzahlen (ÜBERSCHREIBT die alte Balance) + economy.depositPlayer(player, databaseBalance); + + // Logging + plugin.getLogger().info("BALANCE OVERWRITTEN for " + player.getName() + + ": Old=" + currentBalance + ", New=" + databaseBalance + " (from DB)"); + + // Nachricht an Spieler + String message = plugin.getTranslationManager().getMessage("balance-loaded"); + if (message != null && !message.isEmpty()) { + player.sendMessage(plugin.getTranslationManager().formatMessage(message)); + } + }); + + } catch (SQLException e) { + plugin.getPluginLogger().log(Level.SEVERE, + "Failed to load balance for player: " + player.getName(), e); + } + }); + } + + public void savePlayerBalance(OfflinePlayer player) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + try { + double balance = economy.getBalance(player); + databaseManager.saveBalance(player.getUniqueId(), player.getName(), balance); + } catch (SQLException e) { + plugin.getPluginLogger().log(Level.SEVERE, + "Failed to save balance for player: " + player.getName(), e); + } + }); + } + + public void saveAllBalances() { + plugin.getPluginLogger().info("Saving all player balances to database..."); + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + int saved = 0; + for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { + try { + if (economy.hasAccount(player)) { + double balance = economy.getBalance(player); + databaseManager.saveBalance(player.getUniqueId(), player.getName(), balance); + saved++; + } + } catch (SQLException e) { + plugin.getPluginLogger().log(Level.WARNING, + "Failed to save balance for: " + player.getName(), e); + } + } + plugin.getPluginLogger().info("Saved " + saved + " player balances to database."); + }); + } + + public double getCachedBalance(UUID playerUUID) { + OfflinePlayer player = Bukkit.getOfflinePlayer(playerUUID); + if (player != null && economy.hasAccount(player)) { + return economy.getBalance(player); + } + return plugin.getConfigManager().getStartingBalance(); + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/balsync/ConfigManager.java b/src/main/java/com/user404_/balsync/ConfigManager.java new file mode 100644 index 0000000..b5063e7 --- /dev/null +++ b/src/main/java/com/user404_/balsync/ConfigManager.java @@ -0,0 +1,124 @@ +package com.user404_.balsync; + +import org.bukkit.configuration.file.FileConfiguration; +import java.io.File; + +public class ConfigManager { + private final BalSyncPlugin plugin; + private FileConfiguration config; + + public ConfigManager(BalSyncPlugin plugin) { + this.plugin = plugin; + } + + public void loadConfig() { + // Create plugin folder if it doesn't exist + if (!plugin.getDataFolder().exists()) { + plugin.getDataFolder().mkdirs(); + } + + // Save default config from resources + plugin.saveDefaultConfig(); + + // Reload configuration + plugin.reloadConfig(); + config = plugin.getConfig(); + + // Set default values if not present + setDefaults(); + } + + private void setDefaults() { + config.addDefault("database.host", "localhost"); + config.addDefault("database.port", 3306); + config.addDefault("database.database", "minecraft"); + config.addDefault("database.username", "root"); + config.addDefault("database.password", "password"); + config.addDefault("database.use-ssl", false); + config.addDefault("database.connection-pool.maximum-pool-size", 10); + config.addDefault("database.connection-pool.minimum-idle", 5); + config.addDefault("database.connection-pool.connection-timeout", 30000); + config.addDefault("database.connection-pool.idle-timeout", 600000); + + config.addDefault("settings.auto-save-interval", 60); + config.addDefault("settings.save-on-quit", true); + config.addDefault("settings.starting-balance", 100.0); + config.addDefault("settings.locale", "en"); + + config.addDefault("tables.player_balances.table-name", "player_balances"); + config.addDefault("tables.player_balances.uuid-column", "player_uuid"); + config.addDefault("tables.player_balances.balance-column", "balance"); + config.addDefault("tables.player_balances.last-updated-column", "last_updated"); + + config.options().copyDefaults(true); + plugin.saveConfig(); + } + + public void reload() { + plugin.reloadConfig(); + config = plugin.getConfig(); + } + + // Database getters + public String getDatabaseHost() { + return config.getString("database.host", "localhost"); + } + + public int getDatabasePort() { + return config.getInt("database.port", 3306); + } + + public String getDatabaseName() { + return config.getString("database.database", "minecraft"); + } + + public String getDatabaseUsername() { + return config.getString("database.username", "root"); + } + + public String getDatabasePassword() { + return config.getString("database.password", "password"); + } + + public boolean useSSL() { + return config.getBoolean("database.use-ssl", false); + } + + public int getMaxPoolSize() { + return config.getInt("database.connection-pool.maximum-pool-size", 10); + } + + public int getMinIdle() { + return config.getInt("database.connection-pool.minimum-idle", 5); + } + + public int getConnectionTimeout() { + return config.getInt("database.connection-pool.connection-timeout", 30000); + } + + public int getIdleTimeout() { + return config.getInt("database.connection-pool.idle-timeout", 600000); + } + + // Settings getters + public int getAutoSaveInterval() { + return config.getInt("settings.auto-save-interval", 60); + } + + public boolean saveOnQuit() { + return config.getBoolean("settings.save-on-quit", true); + } + + public double getStartingBalance() { + return config.getDouble("settings.starting-balance", 100.0); + } + + public String getLocale() { + return config.getString("settings.locale", "en"); + } + + // Table getters + public String getTableName() { + return config.getString("tables.player_balances.table-name", "player_balances"); + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/balsync/DatabaseManager.java b/src/main/java/com/user404_/balsync/DatabaseManager.java new file mode 100644 index 0000000..c937421 --- /dev/null +++ b/src/main/java/com/user404_/balsync/DatabaseManager.java @@ -0,0 +1,168 @@ +package com.user404_.balsync; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import java.sql.*; +import java.util.UUID; +import java.util.logging.Level; + +public class DatabaseManager { + private final BalSyncPlugin plugin; + private HikariDataSource dataSource; + private final String tableName; + + public DatabaseManager(BalSyncPlugin plugin) { + this.plugin = plugin; + this.tableName = plugin.getConfigManager().getTableName(); + } + + public boolean connect() { + try { + HikariConfig config = new HikariConfig(); + config.setJdbcUrl(String.format("jdbc:mysql://%s:%d/%s", + plugin.getConfigManager().getDatabaseHost(), + plugin.getConfigManager().getDatabasePort(), + plugin.getConfigManager().getDatabaseName())); + config.setUsername(plugin.getConfigManager().getDatabaseUsername()); + config.setPassword(plugin.getConfigManager().getDatabasePassword()); + config.addDataSourceProperty("useSSL", + plugin.getConfigManager().useSSL()); + + // Connection pool settings + config.setMaximumPoolSize(plugin.getConfigManager().getMaxPoolSize()); + config.setMinimumIdle(plugin.getConfigManager().getMinIdle()); + config.setConnectionTimeout(plugin.getConfigManager().getConnectionTimeout()); + config.setIdleTimeout(plugin.getConfigManager().getIdleTimeout()); + config.setLeakDetectionThreshold(30000); + + dataSource = new HikariDataSource(config); + + // Test connection + try (Connection conn = dataSource.getConnection()) { + plugin.getPluginLogger().info("Successfully connected to MySQL database!"); + return true; + } + } catch (SQLException e) { + plugin.getPluginLogger().log(Level.SEVERE, "Failed to connect to database!", e); + return false; + } + } + + public void disconnect() { + if (dataSource != null && !dataSource.isClosed()) { + dataSource.close(); + plugin.getPluginLogger().info("Database connection closed."); + } + } + + public void setupTables() { + // Verwende DECIMAL statt DOUBLE für genauere Währungswerte + double startingBalance = plugin.getConfigManager().getStartingBalance(); + + String createTableSQL = String.format( + "CREATE TABLE IF NOT EXISTS `%s` (" + + "`id` INT AUTO_INCREMENT PRIMARY KEY, " + + "`player_uuid` CHAR(36) UNIQUE NOT NULL, " + + "`player_name` VARCHAR(16), " + + "`balance` DECIMAL(15, 2) NOT NULL DEFAULT %.2f, " + // DECIMAL für bessere Präzision + "`last_updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " + + "INDEX `idx_uuid` (`player_uuid`)" + + ") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB", + tableName, startingBalance + ); + + try (Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement()) { + stmt.execute(createTableSQL); + plugin.getPluginLogger().info("Database tables checked/created successfully!"); + + // Optional: Protokolliere die erstellte Tabelle + logTableInfo(conn); + } catch (SQLException e) { + plugin.getPluginLogger().log(Level.SEVERE, "Failed to create database tables!", e); + + // Fallback-SQL ohne DEFAULT-Wert + tryFallbackTableCreation(); + } + } + + private void logTableInfo(Connection conn) throws SQLException { + String checkSQL = String.format("DESCRIBE `%s`", tableName); + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(checkSQL)) { + plugin.getPluginLogger().info("Table structure for '" + tableName + "':"); + while (rs.next()) { + plugin.getPluginLogger().info(String.format( + "Column: %s, Type: %s, Default: %s", + rs.getString("Field"), + rs.getString("Type"), + rs.getString("Default") + )); + } + } + } + + private void tryFallbackTableCreation() { + plugin.getPluginLogger().warning("Trying fallback table creation..."); + + // Fallback: Tabelle ohne DEFAULT-Wert, dann Standardwert über die Anwendung + String fallbackSQL = String.format( + "CREATE TABLE IF NOT EXISTS `%s` (" + + "`id` INT AUTO_INCREMENT PRIMARY KEY, " + + "`player_uuid` CHAR(36) UNIQUE NOT NULL, " + + "`player_name` VARCHAR(16), " + + "`balance` DECIMAL(15, 2) NOT NULL, " + // Kein DEFAULT hier + "`last_updated` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " + + "INDEX `idx_uuid` (`player_uuid`)" + + ") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB", + tableName + ); + + try (Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement()) { + stmt.execute(fallbackSQL); + plugin.getPluginLogger().info("Fallback table created successfully!"); + } catch (SQLException ex) { + plugin.getPluginLogger().log(Level.SEVERE, "Fallback creation also failed!", ex); + } + } + + public double getBalance(UUID playerUUID) throws SQLException { + String sql = String.format("SELECT balance FROM %s WHERE player_uuid = ?", tableName); + + try (Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, playerUUID.toString()); + + ResultSet rs = stmt.executeQuery(); + if (rs.next()) { + return rs.getDouble("balance"); + } + } + return plugin.getConfigManager().getStartingBalance(); + } + + public void saveBalance(UUID playerUUID, String playerName, double balance) throws SQLException { + String sql = String.format( + "INSERT INTO %s (player_uuid, player_name, balance) VALUES (?, ?, ?) " + + "ON DUPLICATE KEY UPDATE player_name = VALUES(player_name), balance = VALUES(balance)", + tableName + ); + + try (Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, playerUUID.toString()); + stmt.setString(2, playerName); + stmt.setDouble(3, balance); + stmt.executeUpdate(); + } + } + + public Connection getConnection() throws SQLException { + return dataSource.getConnection(); + } + + public boolean isConnected() { + return dataSource != null && !dataSource.isClosed(); + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/balsync/PlayerEventListener.java b/src/main/java/com/user404_/balsync/PlayerEventListener.java new file mode 100644 index 0000000..cdad2dc --- /dev/null +++ b/src/main/java/com/user404_/balsync/PlayerEventListener.java @@ -0,0 +1,33 @@ +package com.user404_.balsync; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerEventListener implements Listener { + private final BalSyncPlugin plugin; + private final BalanceManager balanceManager; + + public PlayerEventListener(BalSyncPlugin plugin, BalanceManager balanceManager) { + this.plugin = plugin; + this.balanceManager = balanceManager; + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + // 2 Sekunden (40 Ticks) Verzögerung + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + if (event.getPlayer().isOnline()) { + balanceManager.loadPlayerBalance(event.getPlayer()); + } + }, 40L); // 20 Ticks = 1 Sekunde, 40 Ticks = 2 Sekunden + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + if (plugin.getConfigManager().saveOnQuit()) { + balanceManager.savePlayerBalance(event.getPlayer()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/user404_/balsync/TranslationManager.java b/src/main/java/com/user404_/balsync/TranslationManager.java new file mode 100644 index 0000000..bb1283e --- /dev/null +++ b/src/main/java/com/user404_/balsync/TranslationManager.java @@ -0,0 +1,93 @@ +package com.user404_.balsync; + +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.FileConfiguration; +import java.io.File; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +public class TranslationManager { + private final BalSyncPlugin plugin; + private final Map messages; + private String locale; + + public TranslationManager(BalSyncPlugin plugin) { + this.plugin = plugin; + this.messages = new HashMap<>(); + } + + public void loadMessages() { + messages.clear(); + locale = plugin.getConfigManager().getLocale(); + + // First, load default messages from JAR + try (Reader reader = new InputStreamReader( + plugin.getResource("messages_en.yml"), StandardCharsets.UTF_8)) { + YamlConfiguration defaultConfig = YamlConfiguration.loadConfiguration(reader); + loadConfigIntoMap(defaultConfig); + } catch (Exception e) { + plugin.getPluginLogger().warning("Failed to load default messages!"); + } + + // Load locale-specific file if different from English + if (!locale.equalsIgnoreCase("en")) { + String fileName = "messages_" + locale.toLowerCase() + ".yml"; + File localeFile = new File(plugin.getDataFolder(), fileName); + + // Copy from resources if doesn't exist + if (!localeFile.exists()) { + plugin.saveResource(fileName, false); + } + + // Load the file + if (localeFile.exists()) { + YamlConfiguration localeConfig = YamlConfiguration.loadConfiguration(localeFile); + loadConfigIntoMap(localeConfig); + } + } + + // Finally, load user overrides from data folder + File userFile = new File(plugin.getDataFolder(), "messages.yml"); + if (userFile.exists()) { + YamlConfiguration userConfig = YamlConfiguration.loadConfiguration(userFile); + loadConfigIntoMap(userConfig); + } + + plugin.getPluginLogger().info("Loaded messages for locale: " + locale); + } + + private void loadConfigIntoMap(YamlConfiguration config) { + for (String key : config.getKeys(true)) { + if (config.isString(key)) { + messages.put(key, config.getString(key)); + } + } + } + + public String getMessage(String key) { + return messages.getOrDefault(key, key); + } + + public String formatMessage(String key, Object... args) { + String message = getMessage(key); + String prefix = getMessage("prefix"); + + if (args.length > 0) { + try { + message = MessageFormat.format(message, args); + } catch (Exception e) { + plugin.getPluginLogger().warning("Failed to format message: " + key); + } + } + + return prefix + message.replace('&', '§'); + } + + public String getLocale() { + return locale; + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..506b8fd --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,32 @@ +# Database Configuration +database: + host: "localhost" + port: 3306 + database: "minecraft" + username: "root" + password: "password" + use-ssl: false + connection-pool: + maximum-pool-size: 10 + minimum-idle: 5 + connection-timeout: 30000 + idle-timeout: 600000 + +# Plugin Settings +settings: + # Auto-save interval in seconds (0 to disable) + auto-save-interval: 60 + # Whether to save on player quit + save-on-quit: true + # Starting balance for new players + starting-balance: 100.0 + # Locale for messages (en, de, etc.) + locale: "en" + +# Database Table Configuration +tables: + player_balances: + table-name: "player_balances" + uuid-column: "player_uuid" + balance-column: "balance" + last-updated-column: "last_updated" \ No newline at end of file diff --git a/src/main/resources/messages_de.yml b/src/main/resources/messages_de.yml new file mode 100644 index 0000000..7da0924 --- /dev/null +++ b/src/main/resources/messages_de.yml @@ -0,0 +1,9 @@ +prefix: "&8[&6BalSync&8] &7" +no-permission: "&cDu hast keine Berechtigung diesen Befehl zu verwenden!" +config-reloaded: "&aKonfiguration erfolgreich neu geladen!" +balance-loaded: "&aDein Kontostand wurde mit der Datenbank synchronisiert." +balance-saved: "&aAlle Spielerkontostände wurden in der Datenbank gespeichert." +database-connected: "&aErfolgreich mit der Datenbank verbunden!" +database-error: "&cDatenbankfehler aufgetreten. Überprüfe die Konsole für Details." +player-not-found: "&cSpieler nicht gefunden!" +usage: "&cVerwendung: /balsync [reload|save|load]" \ No newline at end of file diff --git a/src/main/resources/messages_en.yml b/src/main/resources/messages_en.yml new file mode 100644 index 0000000..a00d43b --- /dev/null +++ b/src/main/resources/messages_en.yml @@ -0,0 +1,9 @@ +prefix: "&8[&6BalSync&8] &7" +no-permission: "&cYou don't have permission to use this command!" +config-reloaded: "&aConfiguration reloaded successfully!" +balance-loaded: "&aYour balance has been synchronized with the database." +balance-saved: "&aAll player balances have been saved to the database." +database-connected: "&aSuccessfully connected to the database!" +database-error: "&cDatabase error occurred. Check console for details." +player-not-found: "&cPlayer not found!" +usage: "&cUsage: /balsync [reload|save|load]" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..e50245e --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,20 @@ +name: BalSync +version: 0.1-alpha +main: com.user404_.balsync.BalSyncPlugin +api-version: '1.20' +description: Synchronizes player balances with MySQL database +author: user404_ +website: https://deutschich.github.io/BalSync + +depend: [Vault] + +commands: + balsync: + description: Main command for BalSync + usage: / [reload|save|load] + permission: balsync.admin + +permissions: + balsync.admin: + description: Allows access to all BalSync commands + default: op \ No newline at end of file