diff --git a/README.md b/README.md index ae79ecb..f1fd2f7 100644 --- a/README.md +++ b/README.md @@ -171,14 +171,30 @@ the new configuration the next time they return to `WAITING`. ```yaml rewards: winner: + money: 100 commands: - - "eco give %player% 100" + - "give %player% diamond 3" - "say %player% won BlockParty in %arena% after %round% rounds!" + +integrations: + vault: true ``` -Commands run as the console, so no Vault/economy plugin is required by BlockParty itself — -if you reference an economy command (like `eco give`) you need that plugin installed -separately. `%player%`, `%arena%` and `%round%` are replaced before dispatch. +Two independent reward mechanisms fire on a win, both optional: + +- **`money`** is deposited straight into the winner's balance through the + [Vault](https://www.spigotmc.org/resources/vault.34315/) Economy API — no console command + string parsing involved. This requires Vault **and** an economy plugin that registers a + Vault `Economy` provider (e.g. EssentialsX, CMI). If Vault or an economy provider isn't + present, BlockParty logs one warning and simply skips the money portion — it never crashes + and console-command rewards still run normally. Set `money: 0` to disable this entirely, or + `integrations.vault: false` to force-disable it even with Vault installed. +- **`commands`** run as the console with `%player%`, `%arena%` and `%round%` substituted, for + anything beyond currency (items, permissions, external plugin hooks, announcements, etc.). + +Vault is declared as a `softdepend` in `plugin.yml`, so BlockParty starts up fine whether or +not it's installed; the Economy service lookup happens fresh each time a reward is dispatched +(not cached at startup), so plugin load order relative to your economy plugin doesn't matter. ## Statistics storage diff --git a/build.gradle b/build.gradle index 301afbe..2ccbbca 100644 --- a/build.gradle +++ b/build.gradle @@ -16,11 +16,15 @@ repositories { mavenCentral() maven { url = 'https://repo.papermc.io/repository/maven-public/' } maven { url = 'https://repo.extendedclip.com/content/repositories/placeholderapi/' } + maven { url = 'https://jitpack.io' } } dependencies { compileOnly 'io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT' compileOnly 'me.clip:placeholderapi:2.11.6' + compileOnly('com.github.MilkBowl:VaultAPI:1.7') { + exclude group: 'org.bukkit', module: 'bukkit' + } implementation 'org.xerial:sqlite-jdbc:3.47.1.0' implementation 'com.mysql:mysql-connector-j:9.1.0' diff --git a/src/main/java/us/tss3/blockparty/arena/Arena.java b/src/main/java/us/tss3/blockparty/arena/Arena.java index 85fecad..71db54c 100644 --- a/src/main/java/us/tss3/blockparty/arena/Arena.java +++ b/src/main/java/us/tss3/blockparty/arena/Arena.java @@ -469,7 +469,7 @@ public class Arena { spawnCelebration(winnerPlayer); } plugin.getStatsManager().recordWin(winner); - plugin.getRewardManager().dispatchWinnerRewards(winnerName, config.getName(), round); + plugin.getRewardManager().dispatchWinnerRewards(winner, winnerName, config.getName(), round); } else { for (UUID uuid : allParticipants()) { Player p = plugin.getServer().getPlayer(uuid); diff --git a/src/main/java/us/tss3/blockparty/config/ConfigManager.java b/src/main/java/us/tss3/blockparty/config/ConfigManager.java index 9250047..4d680f5 100644 --- a/src/main/java/us/tss3/blockparty/config/ConfigManager.java +++ b/src/main/java/us/tss3/blockparty/config/ConfigManager.java @@ -57,6 +57,14 @@ public class ConfigManager { return config.getStringList("rewards.winner.commands"); } + public double getRewardMoney() { + return config.getDouble("rewards.winner.money", 0); + } + + public boolean isVaultEnabled() { + return config.getBoolean("integrations.vault", true); + } + public List getDefaultFloorMaterials() { return config.getStringList("default-floor-materials"); } diff --git a/src/main/java/us/tss3/blockparty/economy/VaultEconomyHook.java b/src/main/java/us/tss3/blockparty/economy/VaultEconomyHook.java new file mode 100644 index 0000000..02c956a --- /dev/null +++ b/src/main/java/us/tss3/blockparty/economy/VaultEconomyHook.java @@ -0,0 +1,36 @@ +package us.tss3.blockparty.economy; + +import net.milkbowl.vault.economy.Economy; +import org.bukkit.OfflinePlayer; +import org.bukkit.plugin.RegisteredServiceProvider; +import us.tss3.blockparty.BlockPartyPlugin; + +/** + * Thin wrapper around the Vault {@link Economy} service. Only ever constructed/touched when + * the Vault plugin is actually present (see BlockPartyPlugin#registerVaultEconomy) so a + * missing Vault install never causes a classloading error on startup. + */ +public class VaultEconomyHook { + + private final Economy economy; + + private VaultEconomyHook(Economy economy) { + this.economy = economy; + } + + /** Returns a hook if Vault is present and has a registered Economy provider, else null. */ + public static VaultEconomyHook tryCreate(BlockPartyPlugin plugin) { + RegisteredServiceProvider rsp = plugin.getServer().getServicesManager().getRegistration(Economy.class); + if (rsp == null || rsp.getProvider() == null) { + return null; + } + return new VaultEconomyHook(rsp.getProvider()); + } + + public boolean deposit(OfflinePlayer player, double amount) { + if (amount <= 0) { + return true; + } + return economy.depositPlayer(player, amount).transactionSuccess(); + } +} diff --git a/src/main/java/us/tss3/blockparty/reward/RewardManager.java b/src/main/java/us/tss3/blockparty/reward/RewardManager.java index 8e57bec..4d076f5 100644 --- a/src/main/java/us/tss3/blockparty/reward/RewardManager.java +++ b/src/main/java/us/tss3/blockparty/reward/RewardManager.java @@ -1,20 +1,33 @@ package us.tss3.blockparty.reward; import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import us.tss3.blockparty.BlockPartyPlugin; +import us.tss3.blockparty.economy.VaultEconomyHook; import java.util.List; +import java.util.UUID; +import java.util.logging.Level; -/** Dispatches configured console commands as rewards, substituting placeholders. No Vault required. */ +/** + * Dispatches configured winner rewards: an optional Vault-backed money deposit + * (rewards.winner.money) plus a list of console commands, both with %player%/%arena%/%round% + * placeholders substituted. Vault is looked up fresh on every dispatch (rather than cached at + * startup) so plugin load order relative to the underlying economy plugin doesn't matter; a + * missing/absent Vault is logged once and simply skips the money portion, never crashing. + */ public class RewardManager { private final BlockPartyPlugin plugin; + private boolean warnedNoVault; public RewardManager(BlockPartyPlugin plugin) { this.plugin = plugin; } - public void dispatchWinnerRewards(String playerName, String arenaName, int round) { + public void dispatchWinnerRewards(UUID playerId, String playerName, String arenaName, int round) { + dispatchMoney(playerId); + List commands = plugin.getConfigManager().getRewardCommands(); for (String cmd : commands) { String parsed = cmd.replace("%player%", playerName) @@ -24,4 +37,37 @@ public class RewardManager { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsed)); } } + + private void dispatchMoney(UUID playerId) { + double amount = plugin.getConfigManager().getRewardMoney(); + if (amount <= 0) { + return; + } + if (!plugin.getConfigManager().isVaultEnabled() || Bukkit.getPluginManager().getPlugin("Vault") == null) { + warnNoVaultOnce(); + return; + } + try { + VaultEconomyHook economy = VaultEconomyHook.tryCreate(plugin); + if (economy == null) { + warnNoVaultOnce(); + return; + } + OfflinePlayer offline = Bukkit.getOfflinePlayer(playerId); + boolean success = economy.deposit(offline, amount); + if (!success) { + plugin.getLogger().warning("Vault deposit of " + amount + " to " + offline.getName() + " reported failure."); + } + } catch (Throwable t) { + plugin.getLogger().log(Level.WARNING, "Failed to deposit winner reward via Vault", t); + } + } + + private void warnNoVaultOnce() { + if (!warnedNoVault) { + plugin.getLogger().warning("rewards.winner.money is set but Vault (with an economy plugin) is not " + + "available - skipping money rewards. Install Vault + an economy plugin, or set money: 0."); + warnedNoVault = true; + } + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1290e6d..118fc1f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -69,9 +69,14 @@ storage: rewards: winner: + # Deposited via the Vault Economy API (requires Vault + an economy plugin like EssentialsX). + # Set to 0 to disable money rewards entirely; console commands below still run either way. + money: 100 commands: - - "eco give %player% 100" + - "give %player% diamond 3" - "say %player% won BlockParty in %arena% after %round% rounds!" integrations: placeholderapi: true + # If false, money rewards are skipped even when Vault is installed (console commands are unaffected). + vault: true