Upload folder via GUI - src
This commit is contained in:
@@ -5,6 +5,7 @@ import net.md_5.bungee.api.config.ListenerInfo;
|
|||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.viper.status.module.ModuleManager;
|
import net.viper.status.module.ModuleManager;
|
||||||
|
import net.viper.status.modules.economy.EconomyModule;
|
||||||
import net.viper.status.modules.antibot.AntiBotModule;
|
import net.viper.status.modules.antibot.AntiBotModule;
|
||||||
import net.viper.status.modules.network.NetworkInfoModule;
|
import net.viper.status.modules.network.NetworkInfoModule;
|
||||||
import net.viper.status.modules.AutoMessage.AutoMessageModule;
|
import net.viper.status.modules.AutoMessage.AutoMessageModule;
|
||||||
@@ -89,6 +90,7 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
moduleManager.registerModule(new AutoMessageModule());
|
moduleManager.registerModule(new AutoMessageModule());
|
||||||
moduleManager.registerModule(new CustomCommandModule());
|
moduleManager.registerModule(new CustomCommandModule());
|
||||||
moduleManager.registerModule(new ServerSwitcherModule());
|
moduleManager.registerModule(new ServerSwitcherModule());
|
||||||
|
moduleManager.registerModule(new EconomyModule());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Class<?> forumBridge = Class.forName("net.viper.status.modules.forum.ForumBridgeModule");
|
Class<?> forumBridge = Class.forName("net.viper.status.modules.forum.ForumBridgeModule");
|
||||||
@@ -506,8 +508,13 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
playerMap.put("playtime", ps.getPlaytimeWithCurrentSession());
|
playerMap.put("playtime", ps.getPlaytimeWithCurrentSession());
|
||||||
playerMap.put("joins", ps.joins);
|
playerMap.put("joins", ps.joins);
|
||||||
playerMap.put("online", ProxyServer.getInstance().getPlayer(ps.uuid) != null);
|
playerMap.put("online", ProxyServer.getInstance().getPlayer(ps.uuid) != null);
|
||||||
|
// Balance direkt aus MySQL (serverübergreifend)
|
||||||
|
EconomyModule ecoModPlayer = (EconomyModule) moduleManager.getModule("EconomyModule");
|
||||||
|
double playerBalance = (ecoModPlayer != null && ecoModPlayer.getManager() != null)
|
||||||
|
? ecoModPlayer.getManager().getBalance(ps.uuid)
|
||||||
|
: ps.balance;
|
||||||
Map<String, Object> economy = new LinkedHashMap<>();
|
Map<String, Object> economy = new LinkedHashMap<>();
|
||||||
economy.put("balance", ps.balance);
|
economy.put("balance", playerBalance);
|
||||||
economy.put("total_earned", ps.totalEarned);
|
economy.put("total_earned", ps.totalEarned);
|
||||||
economy.put("total_spent", ps.totalSpent);
|
economy.put("total_spent", ps.totalSpent);
|
||||||
economy.put("transactions_count", ps.transactionsCount);
|
economy.put("transactions_count", ps.transactionsCount);
|
||||||
@@ -526,49 +533,92 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GET /economy/player?uuid=... oder ?name=...
|
// GET /economy/player?uuid=... oder ?name=...
|
||||||
|
// Kein Cache – UUID und Balance kommen direkt aus der DB
|
||||||
if ("GET".equalsIgnoreCase(method) && "/economy/player".equalsIgnoreCase(pathOnly)) {
|
if ("GET".equalsIgnoreCase(method) && "/economy/player".equalsIgnoreCase(pathOnly)) {
|
||||||
Map<String, String> qp = parseQueryParams(path);
|
Map<String, String> qp = parseQueryParams(path);
|
||||||
StatsModule statsMod = (StatsModule) moduleManager.getModule("StatsModule");
|
EconomyModule ecoModGet = (EconomyModule) moduleManager.getModule("EconomyModule");
|
||||||
PlayerStats ps = resolvePlayer(qp.get("uuid"), qp.get("name"), statsMod);
|
if (ecoModGet == null || ecoModGet.getManager() == null) {
|
||||||
if (ps == null) {
|
sendHttpResponse(out, "{\"success\":false,\"error\":\"economy_module_unavailable\"}", 503);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// UUID auflösen: erst Query-Param, dann Name über EconomyManager (DB-Lookup)
|
||||||
|
UUID ecoUuid = null;
|
||||||
|
String ecoName = null;
|
||||||
|
String uuidParam = qp.get("uuid");
|
||||||
|
String nameParam = qp.get("name");
|
||||||
|
if (uuidParam != null && !uuidParam.isEmpty()) {
|
||||||
|
try { ecoUuid = UUID.fromString(uuidParam.trim()); } catch (IllegalArgumentException ignored) {}
|
||||||
|
}
|
||||||
|
if (ecoUuid == null && nameParam != null && !nameParam.isEmpty()) {
|
||||||
|
ecoUuid = ecoModGet.getManager().resolveUUID(nameParam.trim());
|
||||||
|
ecoName = nameParam.trim();
|
||||||
|
}
|
||||||
|
if (ecoUuid == null) {
|
||||||
sendHttpResponse(out, "{\"success\":false,\"error\":\"player_not_found\"}", 404);
|
sendHttpResponse(out, "{\"success\":false,\"error\":\"player_not_found\"}", 404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ecoName == null) ecoName = uuidParam;
|
||||||
|
double directBalance = ecoModGet.getManager().getBalance(ecoUuid);
|
||||||
Map<String, Object> payload = new LinkedHashMap<>();
|
Map<String, Object> payload = new LinkedHashMap<>();
|
||||||
payload.put("success", true);
|
payload.put("success", true);
|
||||||
payload.put("uuid", ps.uuid.toString());
|
payload.put("uuid", ecoUuid.toString());
|
||||||
payload.put("name", ps.name);
|
payload.put("name", ecoName);
|
||||||
Map<String, Object> economy = new LinkedHashMap<>();
|
Map<String, Object> economy = new LinkedHashMap<>();
|
||||||
economy.put("balance", ps.balance);
|
economy.put("balance", directBalance);
|
||||||
economy.put("total_earned", ps.totalEarned);
|
|
||||||
economy.put("total_spent", ps.totalSpent);
|
|
||||||
economy.put("transactions_count", ps.transactionsCount);
|
|
||||||
payload.put("economy", economy);
|
payload.put("economy", economy);
|
||||||
sendHttpResponse(out, buildJsonString(payload), 200);
|
sendHttpResponse(out, buildJsonString(payload), 200);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /economy/update
|
// POST /economy/update
|
||||||
|
// Kein Cache – Balance wird direkt in die DB geschrieben
|
||||||
if ("POST".equalsIgnoreCase(method) && "/economy/update".equalsIgnoreCase(pathOnly)) {
|
if ("POST".equalsIgnoreCase(method) && "/economy/update".equalsIgnoreCase(pathOnly)) {
|
||||||
String body = readBody(in, headers);
|
String body = readBody(in, headers);
|
||||||
StatsModule statsModEco = (StatsModule) moduleManager.getModule("StatsModule");
|
EconomyModule ecoModUpd = (EconomyModule) moduleManager.getModule("EconomyModule");
|
||||||
PlayerStats psEco = resolvePlayer(extractJsonString(body, "uuid"), extractJsonString(body, "name"), statsModEco);
|
if (ecoModUpd == null || ecoModUpd.getManager() == null) {
|
||||||
if (psEco == null) {
|
sendHttpResponse(out, "{\"success\":false,\"error\":\"economy_module_unavailable\"}", 503);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// UUID auflösen
|
||||||
|
UUID ecoUpdUuid = null;
|
||||||
|
String uuidBody = extractJsonString(body, "uuid");
|
||||||
|
String nameBody = extractJsonString(body, "name");
|
||||||
|
if (uuidBody != null && !uuidBody.isEmpty()) {
|
||||||
|
try { ecoUpdUuid = UUID.fromString(uuidBody.trim()); } catch (IllegalArgumentException ignored) {}
|
||||||
|
}
|
||||||
|
if (ecoUpdUuid == null && nameBody != null && !nameBody.isEmpty()) {
|
||||||
|
ecoUpdUuid = ecoModUpd.getManager().resolveUUID(nameBody.trim());
|
||||||
|
}
|
||||||
|
if (ecoUpdUuid == null) {
|
||||||
sendHttpResponse(out, "{\"success\":false,\"error\":\"player_not_found\"}", 404);
|
sendHttpResponse(out, "{\"success\":false,\"error\":\"player_not_found\"}", 404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String balStr = extractJsonString(body, "balance");
|
// Balance direkt in DB schreiben
|
||||||
String earnStr = extractJsonString(body, "total_earned");
|
String balStr = extractJsonString(body, "balance");
|
||||||
if (earnStr == null) earnStr = extractJsonString(body, "totalEarned");
|
if (balStr != null && !balStr.isEmpty()) {
|
||||||
String spentStr = extractJsonString(body, "total_spent");
|
try {
|
||||||
if (spentStr == null) spentStr = extractJsonString(body, "totalSpent");
|
double newBal = Double.parseDouble(balStr);
|
||||||
String txStr = extractJsonString(body, "transactions_count");
|
ecoModUpd.getManager().setBalance(ecoUpdUuid, newBal);
|
||||||
if (txStr == null) txStr = extractJsonString(body, "transactionsCount");
|
} catch (NumberFormatException ignored) {}
|
||||||
synchronized (psEco) {
|
}
|
||||||
try { if (balStr != null && !balStr.isEmpty()) psEco.balance = Double.parseDouble(balStr); } catch (Exception ignored) {}
|
// Stats-Felder (total_earned etc.) im Cache aktualisieren, falls vorhanden
|
||||||
try { if (earnStr != null && !earnStr.isEmpty()) psEco.totalEarned = Double.parseDouble(earnStr); } catch (Exception ignored) {}
|
StatsModule statsModEco = (StatsModule) moduleManager.getModule("StatsModule");
|
||||||
try { if (spentStr != null && !spentStr.isEmpty()) psEco.totalSpent = Double.parseDouble(spentStr); } catch (Exception ignored) {}
|
if (statsModEco != null) {
|
||||||
try { if (txStr != null && !txStr.isEmpty()) psEco.transactionsCount = Integer.parseInt(txStr); } catch (Exception ignored) {}
|
PlayerStats psEco = statsModEco.getManager().getIfPresent(ecoUpdUuid);
|
||||||
|
if (psEco != null) {
|
||||||
|
String earnStr = extractJsonString(body, "total_earned");
|
||||||
|
if (earnStr == null) earnStr = extractJsonString(body, "totalEarned");
|
||||||
|
String spentStr = extractJsonString(body, "total_spent");
|
||||||
|
if (spentStr == null) spentStr = extractJsonString(body, "totalSpent");
|
||||||
|
String txStr = extractJsonString(body, "transactions_count");
|
||||||
|
if (txStr == null) txStr = extractJsonString(body, "transactionsCount");
|
||||||
|
synchronized (psEco) {
|
||||||
|
try { if (balStr != null && !balStr.isEmpty()) psEco.balance = Double.parseDouble(balStr); } catch (Exception ignored) {}
|
||||||
|
try { if (earnStr != null && !earnStr.isEmpty()) psEco.totalEarned = Double.parseDouble(earnStr); } catch (Exception ignored) {}
|
||||||
|
try { if (spentStr != null && !spentStr.isEmpty()) psEco.totalSpent = Double.parseDouble(spentStr); } catch (Exception ignored) {}
|
||||||
|
try { if (txStr != null && !txStr.isEmpty()) psEco.transactionsCount = Integer.parseInt(txStr); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sendHttpResponse(out, "{\"success\":true}", 200);
|
sendHttpResponse(out, "{\"success\":true}", 200);
|
||||||
return;
|
return;
|
||||||
@@ -690,8 +740,13 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
playerInfo.put("joins", ps.joins);
|
playerInfo.put("joins", ps.joins);
|
||||||
playerInfo.put("first_seen", ps.firstSeen);
|
playerInfo.put("first_seen", ps.firstSeen);
|
||||||
playerInfo.put("last_seen", ps.lastSeen);
|
playerInfo.put("last_seen", ps.lastSeen);
|
||||||
|
// Balance direkt aus MySQL (serverübergreifend)
|
||||||
|
EconomyModule ecoModStatus = (EconomyModule) moduleManager.getModule("EconomyModule");
|
||||||
|
double statusBalance = (ecoModStatus != null && ecoModStatus.getManager() != null)
|
||||||
|
? ecoModStatus.getManager().getBalance(p.getUniqueId())
|
||||||
|
: ps.balance;
|
||||||
Map<String, Object> eco = new LinkedHashMap<>();
|
Map<String, Object> eco = new LinkedHashMap<>();
|
||||||
eco.put("balance", ps.balance);
|
eco.put("balance", statusBalance);
|
||||||
eco.put("total_earned", ps.totalEarned);
|
eco.put("total_earned", ps.totalEarned);
|
||||||
eco.put("total_spent", ps.totalSpent);
|
eco.put("total_spent", ps.totalSpent);
|
||||||
eco.put("transactions_count", ps.transactionsCount);
|
eco.put("transactions_count", ps.transactionsCount);
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /ecoadmin <give|take|set|check> <Spieler> [Betrag]
|
||||||
|
* Admin-Verwaltung des Economy-Systems (auch für Offline-Spieler).
|
||||||
|
*
|
||||||
|
* Berechtigung: economy.admin
|
||||||
|
*/
|
||||||
|
public class EcoAdminCommand extends Command {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final EconomyManager manager;
|
||||||
|
|
||||||
|
public EcoAdminCommand(Plugin plugin, EconomyManager manager) {
|
||||||
|
super("ecoadmin", "economy.admin", "ecomod", "moneyadmin");
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, String[] args) {
|
||||||
|
if (!sender.hasPermission("economy.admin")) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cKeine Berechtigung.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sendHelp(sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String action = args[0].toLowerCase();
|
||||||
|
String targetName = args[1];
|
||||||
|
|
||||||
|
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||||
|
UUID targetUUID = manager.resolveUUID(targetName);
|
||||||
|
|
||||||
|
if (targetUUID == null) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cSpieler &e" + targetName + " &cnicht gefunden.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
|
||||||
|
case "check": {
|
||||||
|
double bal = manager.getBalance(targetUUID);
|
||||||
|
sender.sendMessage(new TextComponent(c("&7Kontostand von &e" + targetName
|
||||||
|
+ "&7: &a" + formatAmount(bal) + " $")));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "give": {
|
||||||
|
if (args.length < 3) { sendHelp(sender); return; }
|
||||||
|
double amount = parseAmount(args[2]);
|
||||||
|
if (amount <= 0) { sender.sendMessage(new TextComponent(c("&cUngültiger Betrag."))); return; }
|
||||||
|
manager.deposit(targetUUID, amount);
|
||||||
|
double newBal = manager.getBalance(targetUUID);
|
||||||
|
sender.sendMessage(new TextComponent(c("&a+ " + formatAmount(amount)
|
||||||
|
+ " $ &7an &e" + targetName + " &7→ Neues Guthaben: &a" + formatAmount(newBal) + " $")));
|
||||||
|
notifyPlayer(targetUUID, c("&7Admin hat dir &a+" + formatAmount(amount)
|
||||||
|
+ " $ &7gegeben. Guthaben: &a" + formatAmount(newBal) + " $"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "take": {
|
||||||
|
if (args.length < 3) { sendHelp(sender); return; }
|
||||||
|
double amount = parseAmount(args[2]);
|
||||||
|
if (amount <= 0) { sender.sendMessage(new TextComponent(c("&cUngültiger Betrag."))); return; }
|
||||||
|
boolean ok = manager.withdraw(targetUUID, amount);
|
||||||
|
if (!ok) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cNicht genug Guthaben bei &e" + targetName + "&c.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double newBal = manager.getBalance(targetUUID);
|
||||||
|
sender.sendMessage(new TextComponent(c("&c- " + formatAmount(amount)
|
||||||
|
+ " $ &7von &e" + targetName + " &7→ Neues Guthaben: &a" + formatAmount(newBal) + " $")));
|
||||||
|
notifyPlayer(targetUUID, c("&7Admin hat dir &c-" + formatAmount(amount)
|
||||||
|
+ " $ &7abgezogen. Guthaben: &a" + formatAmount(newBal) + " $"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "set": {
|
||||||
|
if (args.length < 3) { sendHelp(sender); return; }
|
||||||
|
double amount = parseAmount(args[2]);
|
||||||
|
if (amount < 0) { sender.sendMessage(new TextComponent(c("&cBetrag darf nicht negativ sein."))); return; }
|
||||||
|
manager.setBalance(targetUUID, amount);
|
||||||
|
sender.sendMessage(new TextComponent(c("&7Guthaben von &e" + targetName
|
||||||
|
+ " &7gesetzt auf &a" + formatAmount(amount) + " $")));
|
||||||
|
notifyPlayer(targetUUID, c("&7Dein Guthaben wurde auf &a" + formatAmount(amount) + " $ &7gesetzt."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
sendHelp(sender);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyPlayer(UUID uuid, String message) {
|
||||||
|
ProxiedPlayer target = plugin.getProxy().getPlayer(uuid);
|
||||||
|
if (target != null) {
|
||||||
|
target.sendMessage(new TextComponent(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHelp(CommandSender sender) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&e/ecoadmin check <Spieler>")));
|
||||||
|
sender.sendMessage(new TextComponent(c("&e/ecoadmin give <Spieler> <Betrag>")));
|
||||||
|
sender.sendMessage(new TextComponent(c("&e/ecoadmin take <Spieler> <Betrag>")));
|
||||||
|
sender.sendMessage(new TextComponent(c("&e/ecoadmin set <Spieler> <Betrag>")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double parseAmount(String s) {
|
||||||
|
try { return Double.parseDouble(s.replace(",", ".")); }
|
||||||
|
catch (NumberFormatException e) { return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatAmount(double amount) {
|
||||||
|
return String.format("%,.2f", amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String c(String msg) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verwaltet die MySQL-Verbindung (HikariCP) und die Tabelle bc_accounts.
|
||||||
|
* Wird vom EconomyModule gehalten und an den EconomyManager weitergegeben.
|
||||||
|
*/
|
||||||
|
public class EconomyDatabase {
|
||||||
|
|
||||||
|
private static final String TABLE = "bc_accounts";
|
||||||
|
|
||||||
|
private final Logger log;
|
||||||
|
private HikariDataSource dataSource;
|
||||||
|
|
||||||
|
public EconomyDatabase(Plugin plugin, String host, int port, String database, String user, String password) {
|
||||||
|
this.log = plugin.getLogger();
|
||||||
|
|
||||||
|
HikariConfig cfg = new HikariConfig();
|
||||||
|
cfg.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database
|
||||||
|
+ "?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&useUnicode=true");
|
||||||
|
cfg.setUsername(user);
|
||||||
|
cfg.setPassword(password);
|
||||||
|
cfg.setMaximumPoolSize(5);
|
||||||
|
cfg.setMinimumIdle(1);
|
||||||
|
cfg.setConnectionTimeout(10_000);
|
||||||
|
cfg.setIdleTimeout(600_000);
|
||||||
|
cfg.setMaxLifetime(1_800_000);
|
||||||
|
cfg.setPoolName("StatusAPI-Economy");
|
||||||
|
cfg.addDataSourceProperty("cachePrepStmts", "true");
|
||||||
|
cfg.addDataSourceProperty("prepStmtCacheSize", "250");
|
||||||
|
cfg.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
||||||
|
|
||||||
|
try {
|
||||||
|
dataSource = new HikariDataSource(cfg);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.severe("[Economy] MySQL-Verbindung fehlgeschlagen: " + e.getMessage());
|
||||||
|
log.severe("[Economy] Bitte Zugangsdaten in verify.properties prüfen!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tabelle anlegen falls nicht vorhanden (kompatibel mit SurvivalPlus)
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"CREATE TABLE IF NOT EXISTS `" + TABLE + "` (" +
|
||||||
|
" `player_name` VARCHAR(36) NOT NULL," +
|
||||||
|
" `balance` VARCHAR(255) NOT NULL DEFAULT '0'," +
|
||||||
|
" PRIMARY KEY (`player_name`)" +
|
||||||
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")) {
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.severe("[Economy] Tabellen-Setup (bc_accounts) fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// bc_player_names Tabelle anlegen
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"CREATE TABLE IF NOT EXISTS `bc_player_names` (" +
|
||||||
|
" `uuid` VARCHAR(36) NOT NULL PRIMARY KEY," +
|
||||||
|
" `name` VARCHAR(16) NOT NULL," +
|
||||||
|
" `updated` BIGINT NOT NULL" +
|
||||||
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")) {
|
||||||
|
ps.executeUpdate();
|
||||||
|
log.info("[Economy] MySQL verbunden – Tabellen bereit.");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.severe("[Economy] Tabellen-Setup (bc_player_names) fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return dataSource != null && !dataSource.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
if (dataSource != null && !dataSource.isClosed()) {
|
||||||
|
dataSource.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sucht UUID in CMI_users – nutzt eine separate DB-Verbindung falls
|
||||||
|
* economy.cmi.database konfiguriert ist, sonst dieselbe DB.
|
||||||
|
*/
|
||||||
|
public java.util.UUID findUUIDByName(String name) {
|
||||||
|
if (!isConnected()) return null;
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"SELECT `player_uuid` FROM `CMI_users` WHERE `username` = ? LIMIT 1")) {
|
||||||
|
ps.setString(1, name);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
String uuidStr = rs.getString("player_uuid");
|
||||||
|
if (uuidStr != null && !uuidStr.isEmpty()) {
|
||||||
|
return java.util.UUID.fromString(uuidStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | IllegalArgumentException e) {
|
||||||
|
// CMI_users nicht in dieser DB – kein Problem, bc_player_names ist der Primär-Lookup
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Speichert den Spielernamen in einer eigenen Lookup-Tabelle. */
|
||||||
|
public void saveNameMapping(java.util.UUID uuid, String name) {
|
||||||
|
if (!isConnected()) return;
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"INSERT INTO `bc_player_names` (`uuid`, `name`, `updated`) VALUES (?, ?, ?) " +
|
||||||
|
"ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `updated` = VALUES(`updated`)")) {
|
||||||
|
ps.setString(1, uuid.toString());
|
||||||
|
ps.setString(2, name);
|
||||||
|
ps.setLong(3, System.currentTimeMillis());
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.warning("[Economy] Name-Mapping fehlgeschlagen: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** UUID-Lookup über bc_player_names (eigene Tabelle). */
|
||||||
|
public java.util.UUID findUUIDByNameOwn(String name) {
|
||||||
|
if (!isConnected()) return null;
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"SELECT `uuid` FROM `bc_player_names` WHERE `name` = ? LIMIT 1")) {
|
||||||
|
ps.setString(1, name);
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return java.util.UUID.fromString(rs.getString("uuid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | IllegalArgumentException e) {
|
||||||
|
// Tabelle noch nicht vorhanden
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Kombinierter UUID-Lookup: erst eigene Tabelle, dann CMI_users. */
|
||||||
|
public java.util.UUID resolveUUID(String name) {
|
||||||
|
java.util.UUID uuid = findUUIDByNameOwn(name);
|
||||||
|
if (uuid != null) return uuid;
|
||||||
|
return findUUIDByName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Lädt den Kontostand direkt aus der DB. Gibt -1 zurück wenn kein Eintrag. */
|
||||||
|
public double load(UUID uuid) {
|
||||||
|
if (!isConnected()) return -1;
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"SELECT `balance` FROM `" + TABLE + "` WHERE `player_name` = ?")) {
|
||||||
|
ps.setString(1, uuid.toString());
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return Double.parseDouble(rs.getString("balance"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException | NumberFormatException e) {
|
||||||
|
log.warning("[Economy] Load fehlgeschlagen für " + uuid + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Schreibt einen Kontostand in die DB (INSERT oder UPDATE). */
|
||||||
|
public void save(UUID uuid, double balance) {
|
||||||
|
if (!isConnected()) return;
|
||||||
|
try (Connection con = dataSource.getConnection();
|
||||||
|
PreparedStatement ps = con.prepareStatement(
|
||||||
|
"INSERT INTO `" + TABLE + "` (`player_name`, `balance`) VALUES (?, ?) " +
|
||||||
|
"ON DUPLICATE KEY UPDATE `balance` = VALUES(`balance`)")) {
|
||||||
|
ps.setString(1, uuid.toString());
|
||||||
|
ps.setString(2, String.valueOf(balance));
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.warning("[Economy] Save fehlgeschlagen für " + uuid + ": " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
|
||||||
|
public class EconomyListener implements Listener {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final EconomyManager manager;
|
||||||
|
|
||||||
|
public EconomyListener(Plugin plugin, EconomyManager manager) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beim ersten Login: Konto anlegen falls noch nicht vorhanden.
|
||||||
|
* Kein Caching – alle weiteren Zugriffe gehen direkt in die DB.
|
||||||
|
*/
|
||||||
|
@EventHandler
|
||||||
|
public void onLogin(PostLoginEvent event) {
|
||||||
|
ProxiedPlayer player = event.getPlayer();
|
||||||
|
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||||
|
// Namen für Offline-Lookup speichern
|
||||||
|
manager.saveNameMapping(player.getUniqueId(), player.getName());
|
||||||
|
// Konto anlegen falls neu
|
||||||
|
manager.getBalance(player.getUniqueId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kein Cache – jeder Zugriff geht direkt in die Datenbank.
|
||||||
|
* Damit ist der Kontostand immer aktuell, egal von welchem Server
|
||||||
|
* er zuletzt geändert wurde (SurvivalPlus, CMI, etc.).
|
||||||
|
*/
|
||||||
|
public class EconomyManager {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final EconomyDatabase db;
|
||||||
|
private final double startBalance;
|
||||||
|
|
||||||
|
public EconomyManager(Plugin plugin, EconomyDatabase db, double startBalance) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.db = db;
|
||||||
|
this.startBalance = startBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveNameMapping(UUID uuid, String name) {
|
||||||
|
db.saveNameMapping(uuid, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID resolveUUID(String name) {
|
||||||
|
// 1. Online-Spieler auf dem Proxy (case-insensitive)
|
||||||
|
for (net.md_5.bungee.api.connection.ProxiedPlayer p : plugin.getProxy().getPlayers()) {
|
||||||
|
if (p.getName().equalsIgnoreCase(name)) return p.getUniqueId();
|
||||||
|
}
|
||||||
|
// 2. Eigene bc_player_names Tabelle
|
||||||
|
UUID uuid = db.findUUIDByNameOwn(name);
|
||||||
|
if (uuid != null) return uuid;
|
||||||
|
// 3. CMI_users Fallback
|
||||||
|
uuid = db.findUUIDByName(name);
|
||||||
|
if (uuid != null) return uuid;
|
||||||
|
// 4. Mojang API als letzter Ausweg
|
||||||
|
return lookupMojang(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** UUID via Mojang API holen (nur wenn alle lokalen Lookups fehlschlagen). */
|
||||||
|
private UUID lookupMojang(String name) {
|
||||||
|
try {
|
||||||
|
java.net.URL url = new java.net.URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||||
|
java.net.HttpURLConnection con = (java.net.HttpURLConnection) url.openConnection();
|
||||||
|
con.setConnectTimeout(3000);
|
||||||
|
con.setReadTimeout(3000);
|
||||||
|
con.setRequestMethod("GET");
|
||||||
|
if (con.getResponseCode() != 200) return null;
|
||||||
|
java.io.BufferedReader br = new java.io.BufferedReader(
|
||||||
|
new java.io.InputStreamReader(con.getInputStream()));
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) sb.append(line);
|
||||||
|
br.close();
|
||||||
|
String json = sb.toString();
|
||||||
|
int idIdx = json.indexOf("\"id\":\"");
|
||||||
|
if (idIdx < 0) return null;
|
||||||
|
String raw = json.substring(idIdx + 6, idIdx + 38);
|
||||||
|
String formatted = raw.replaceFirst(
|
||||||
|
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
|
||||||
|
UUID uuid = UUID.fromString(formatted);
|
||||||
|
// Für künftige Lookups speichern
|
||||||
|
db.saveNameMapping(uuid, name);
|
||||||
|
plugin.getLogger().info("[Economy] Mojang-Lookup: " + name + " → " + uuid);
|
||||||
|
return uuid;
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().warning("[Economy] Mojang-Lookup fehlgeschlagen für " + name + ": " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getBalance(UUID uuid) {
|
||||||
|
double bal = db.load(uuid);
|
||||||
|
if (bal < 0) {
|
||||||
|
// Neuer Spieler – Startkonto anlegen
|
||||||
|
db.save(uuid, startBalance);
|
||||||
|
return startBalance;
|
||||||
|
}
|
||||||
|
return bal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBalance(UUID uuid, double amount) {
|
||||||
|
db.save(uuid, Math.max(0.0, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deposit(UUID uuid, double amount) {
|
||||||
|
if (amount <= 0) return false;
|
||||||
|
double current = db.load(uuid);
|
||||||
|
if (current < 0) current = startBalance;
|
||||||
|
db.save(uuid, current + amount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean withdraw(UUID uuid, double amount) {
|
||||||
|
if (amount <= 0) return false;
|
||||||
|
double current = db.load(uuid);
|
||||||
|
if (current < 0) current = 0;
|
||||||
|
if (current < amount) return false;
|
||||||
|
db.save(uuid, current - amount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAccount(UUID uuid) {
|
||||||
|
return db.load(uuid) >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
|
import net.viper.status.module.Module;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EconomyModule – serverübergreifendes Geldkonto über MySQL (bc_accounts).
|
||||||
|
*
|
||||||
|
* Konfiguration in verify.properties:
|
||||||
|
* economy.mysql.host=localhost
|
||||||
|
* economy.mysql.port=3306
|
||||||
|
* economy.mysql.database=survivalplus
|
||||||
|
* economy.mysql.username=root
|
||||||
|
* economy.mysql.password=
|
||||||
|
* economy.start-balance=500.0
|
||||||
|
*
|
||||||
|
* Das Modul registriert sich im Modul-System der StatusAPI und hält
|
||||||
|
* EconomyDatabase + EconomyManager, die von SurvivalPlus und allen
|
||||||
|
* anderen Servern über die gemeinsame bc_accounts-Tabelle genutzt werden.
|
||||||
|
*/
|
||||||
|
public class EconomyModule implements Module {
|
||||||
|
|
||||||
|
private EconomyDatabase database;
|
||||||
|
private EconomyManager manager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "EconomyModule";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable(Plugin plugin) {
|
||||||
|
// Konfiguration aus verify.properties laden
|
||||||
|
Properties props = ((StatusAPI) plugin).getVerifyProperties();
|
||||||
|
|
||||||
|
String host = getProp(props, "economy.mysql.host", "localhost");
|
||||||
|
int port = getInt (props, "economy.mysql.port", 3306);
|
||||||
|
String database = getProp(props, "economy.mysql.database", "survivalplus");
|
||||||
|
String user = getProp(props, "economy.mysql.username", "root");
|
||||||
|
String password = getProp(props, "economy.mysql.password", "");
|
||||||
|
double startBal = getDbl (props, "economy.start-balance", 500.0);
|
||||||
|
|
||||||
|
this.database = new EconomyDatabase(plugin, host, port, database, user, password);
|
||||||
|
|
||||||
|
if (!this.database.isConnected()) {
|
||||||
|
plugin.getLogger().severe("[Economy] Modul wird NICHT aktiviert – keine DB-Verbindung.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.manager = new EconomyManager(plugin, this.database, startBal);
|
||||||
|
|
||||||
|
// Listener registrieren (Login → load, Disconnect → save)
|
||||||
|
plugin.getProxy().getPluginManager().registerListener(plugin, new EconomyListener(plugin, manager));
|
||||||
|
plugin.getProxy().getPluginManager().registerCommand(plugin, new PayCommand(plugin, manager));
|
||||||
|
plugin.getProxy().getPluginManager().registerCommand(plugin, new EcoAdminCommand(plugin, manager));
|
||||||
|
|
||||||
|
plugin.getLogger().info("[Economy] EconomyModule aktiviert (start-balance: " + startBal + ").");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable(Plugin plugin) {
|
||||||
|
if (database != null) {
|
||||||
|
database.close();
|
||||||
|
plugin.getLogger().info("[Economy] MySQL-Verbindung geschlossen.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gibt den EconomyManager zurück (für andere Module oder HTTP-Endpoints). */
|
||||||
|
public EconomyManager getManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// Hilfsmethoden
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
private static String getProp(Properties p, String key, String def) {
|
||||||
|
if (p == null) return def;
|
||||||
|
String v = p.getProperty(key, def);
|
||||||
|
return (v == null || v.trim().isEmpty()) ? def : v.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getInt(Properties p, String key, int def) {
|
||||||
|
try { return Integer.parseInt(getProp(p, key, String.valueOf(def))); }
|
||||||
|
catch (NumberFormatException e) { return def; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double getDbl(Properties p, String key, double def) {
|
||||||
|
try { return Double.parseDouble(getProp(p, key, String.valueOf(def))); }
|
||||||
|
catch (NumberFormatException e) { return def; }
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/main/java/net/viper/status/modules/economy/PayCommand.java
Normal file
102
src/main/java/net/viper/status/modules/economy/PayCommand.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* /pay <Spieler> <Betrag>
|
||||||
|
* Überweist Geld an einen anderen Spieler (auch offline).
|
||||||
|
*/
|
||||||
|
public class PayCommand extends Command {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final EconomyManager manager;
|
||||||
|
|
||||||
|
public PayCommand(Plugin plugin, EconomyManager manager) {
|
||||||
|
super("pay", null);
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, String[] args) {
|
||||||
|
if (!(sender instanceof ProxiedPlayer)) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cNur Spieler können diesen Befehl nutzen.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&eVerwendung: &f/pay <Spieler> <Betrag>")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProxiedPlayer payer = (ProxiedPlayer) sender;
|
||||||
|
String targetName = args[0];
|
||||||
|
double amount;
|
||||||
|
|
||||||
|
try {
|
||||||
|
amount = Double.parseDouble(args[1].replace(",", "."));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cUngültiger Betrag.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount <= 0) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cDer Betrag muss größer als 0 sein.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetName.equalsIgnoreCase(payer.getName())) {
|
||||||
|
sender.sendMessage(new TextComponent(c("&cDu kannst dir nicht selbst Geld überweisen.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||||
|
UUID targetUUID = manager.resolveUUID(targetName);
|
||||||
|
|
||||||
|
if (targetUUID == null) {
|
||||||
|
payer.sendMessage(new TextComponent(c("&cSpieler &e" + targetName + " &cnicht gefunden.")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double payerBalance = manager.getBalance(payer.getUniqueId());
|
||||||
|
|
||||||
|
if (payerBalance < amount) {
|
||||||
|
payer.sendMessage(new TextComponent(c("&cNicht genug Guthaben. Dein Kontostand: &e"
|
||||||
|
+ formatAmount(payerBalance) + " $")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.withdraw(payer.getUniqueId(), amount);
|
||||||
|
manager.deposit(targetUUID, amount);
|
||||||
|
|
||||||
|
payer.sendMessage(new TextComponent(c("&aErfolgreich &e" + formatAmount(amount)
|
||||||
|
+ " $ &aan &e" + targetName + " &aüberwiesen.")));
|
||||||
|
payer.sendMessage(new TextComponent(c("&7Dein neues Guthaben: &e"
|
||||||
|
+ formatAmount(manager.getBalance(payer.getUniqueId())) + " $")));
|
||||||
|
|
||||||
|
// Online-Benachrichtigung an Empfänger
|
||||||
|
ProxiedPlayer target = plugin.getProxy().getPlayer(targetUUID);
|
||||||
|
if (target != null) {
|
||||||
|
target.sendMessage(new TextComponent(c("&a" + payer.getName()
|
||||||
|
+ " hat dir &e" + formatAmount(amount) + " $ &aüberwiesen.")));
|
||||||
|
target.sendMessage(new TextComponent(c("&7Dein neues Guthaben: &e"
|
||||||
|
+ formatAmount(manager.getBalance(targetUUID)) + " $")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatAmount(double amount) {
|
||||||
|
return String.format("%,.2f", amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String c(String msg) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,17 @@ softdepend:
|
|||||||
- Geyser-BungeeCord
|
- Geyser-BungeeCord
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
|
# ── Economy ───────────────────────────────────────────────
|
||||||
|
pay:
|
||||||
|
description: Überweise Geld an einen Spieler (auch offline)
|
||||||
|
usage: /pay <Spieler> <Betrag>
|
||||||
|
|
||||||
|
ecoadmin:
|
||||||
|
description: Admin-Verwaltung des Economy-Systems
|
||||||
|
usage: /ecoadmin <give|take|set|check> <Spieler> [Betrag]
|
||||||
|
permission: economy.admin
|
||||||
|
aliases: [ecomod, moneyadmin]
|
||||||
|
|
||||||
# ── VanishModule ──────────────────────────────────────────
|
# ── VanishModule ──────────────────────────────────────────
|
||||||
vanish:
|
vanish:
|
||||||
description: Vanish ein-/ausschalten
|
description: Vanish ein-/ausschalten
|
||||||
|
|||||||
@@ -80,3 +80,16 @@ automessage.prefix=
|
|||||||
|
|
||||||
# Der Name der Datei, in der die Nachrichten stehen (liegt im Plugin-Ordner)
|
# Der Name der Datei, in der die Nachrichten stehen (liegt im Plugin-Ordner)
|
||||||
automessage.file=messages.txt
|
automessage.file=messages.txt
|
||||||
|
|
||||||
|
|
||||||
|
# ===========================
|
||||||
|
# ECONOMY (Serverübergreifendes Geld)
|
||||||
|
# ===========================
|
||||||
|
# Alle Server (SurvivalPlus + StatusAPI/BungeeCord) müssen dieselbe Datenbank nutzen.
|
||||||
|
# Die Tabelle bc_accounts wird automatisch erstellt.
|
||||||
|
economy.mysql.host=localhost
|
||||||
|
economy.mysql.port=3306
|
||||||
|
economy.mysql.database=survivalplus
|
||||||
|
economy.mysql.username=root
|
||||||
|
economy.mysql.password=
|
||||||
|
economy.start-balance=500.0
|
||||||
|
|||||||
Reference in New Issue
Block a user