Initial Commit

This commit is contained in:
2025-12-01 19:21:26 +01:00
parent 6e6c0e4e85
commit 2065559155
13 changed files with 983 additions and 0 deletions

113
.gitignore vendored Normal file
View File

@@ -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/

97
pom.xml Normal file
View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.user404_</groupId>
<artifactId>BalSync</artifactId>
<version>0.1-alpha</version>
<packaging>jar</packaging>
<name>BalSync</name>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<defaultGoal>clean package</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<!-- PaperMC Repository -->
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<!-- VaultAPI Repository (JitPack) -->
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- VaultAPI -->
<dependency>
<groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- HikariCP for Connection Pooling -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
</dependencies>
</project>

View File

@@ -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;
}
}

View File

@@ -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<Economy> 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;
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}

View File

@@ -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();
}
}

View File

@@ -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());
}
}
}

View File

@@ -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<String, String> 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;
}
}

View File

@@ -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"

View File

@@ -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]"

View File

@@ -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]"

View File

@@ -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: /<command> [reload|save|load]
permission: balsync.admin
permissions:
balsync.admin:
description: Allows access to all BalSync commands
default: op