Dieser Commit ist enthalten in:
Silent 2022-02-25 18:57:32 +01:00
Ursprung dab244044a
Commit 0b48a14f1c
27 geänderte Dateien mit 573 neuen und 303 gelöschten Zeilen

Datei anzeigen

@ -6,7 +6,7 @@
<groupId>tsp.headdb</groupId>
<artifactId>HeadDB</artifactId>
<version>3.3.0</version>
<version>4.0.0</version>
<packaging>jar</packaging>
<name>HeadDB</name>
@ -63,6 +63,13 @@
<version>1.7</version>
<scope>provided</scope>
</dependency>
<!-- Treasury -->
<dependency>
<groupId>me.lokka30</groupId>
<artifactId>treasury-api</artifactId>
<version>1.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

Datei anzeigen

@ -3,9 +3,10 @@ package tsp.headdb;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.command.CommandHeadDB;
import tsp.headdb.database.DatabaseUpdateTask;
import tsp.headdb.economy.HEconomyProvider;
import tsp.headdb.command.HeadDBCommand;
import tsp.headdb.economy.TreasuryProvider;
import tsp.headdb.implementation.DatabaseUpdateTask;
import tsp.headdb.economy.BasicEconomyProvider;
import tsp.headdb.economy.VaultProvider;
import tsp.headdb.listener.JoinListener;
import tsp.headdb.listener.MenuListener;
@ -22,7 +23,7 @@ import java.io.File;
public class HeadDB extends JavaPlugin {
private static HeadDB instance;
private HEconomyProvider economyProvider;
private BasicEconomyProvider economyProvider;
private PlayerDataFile playerData;
private Localization localization;
@ -42,11 +43,14 @@ public class HeadDB extends JavaPlugin {
if (rawProvider.equalsIgnoreCase("vault")) {
economyProvider = new VaultProvider();
economyProvider.initProvider();
} else if (rawProvider.equalsIgnoreCase("treasury")) {
economyProvider = new TreasuryProvider();
economyProvider.initProvider();
}
}
long refresh = getConfig().getLong("refresh") * 20;
HeadAPI.getDatabase().updateAsync(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!")); // Update database on startup
HeadAPI.getDatabase().update(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!")); // Update database on startup
Bukkit.getScheduler().runTaskTimerAsynchronously(this, new DatabaseUpdateTask(), refresh, refresh); // Update database on set interval (also saves data)
HeadAPI.getDatabase().setRefresh(refresh);
@ -54,7 +58,7 @@ public class HeadDB extends JavaPlugin {
new MenuListener(this);
new PagedPaneListener(this);
getCommand("headdb").setExecutor(new CommandHeadDB());
getCommand("headdb").setExecutor(new HeadDBCommand());
Log.debug("Starting metrics...");
new Metrics(this, 9152);
@ -83,7 +87,7 @@ public class HeadDB extends JavaPlugin {
}
@Nullable
public HEconomyProvider getEconomyProvider() {
public BasicEconomyProvider getEconomyProvider() {
return economyProvider;
}

Datei anzeigen

@ -4,8 +4,10 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import tsp.headdb.HeadDB;
import tsp.headdb.database.Category;
import tsp.headdb.database.HeadDatabase;
import tsp.headdb.implementation.Category;
import tsp.headdb.implementation.Head;
import tsp.headdb.implementation.HeadDatabase;
import tsp.headdb.implementation.LocalHead;
import tsp.headdb.inventory.InventoryUtils;
import tsp.headdb.storage.PlayerDataFile;
@ -14,6 +16,7 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* This class provides simple methods
@ -21,7 +24,6 @@ import java.util.UUID;
*
* @author TheSilentPro
*/
// TODO: Possibly change to singleton class
public final class HeadAPI {
private HeadAPI() {}
@ -195,14 +197,9 @@ public final class HeadAPI {
*/
@Nonnull
public static List<Head> getFavoriteHeads(UUID uuid) {
List<Head> result = new ArrayList<>();
List<String> textures = HeadDB.getInstance().getPlayerData().getFavoriteHeadsByTexture(uuid);
for (String texture : textures) {
result.add(HeadAPI.getHeadByValue(texture));
}
return result;
return HeadDB.getInstance().getPlayerData().getFavoriteHeadsByTexture(uuid).stream()
.map(HeadAPI::getHeadByValue)
.collect(Collectors.toList());
}
/**
@ -214,13 +211,10 @@ public final class HeadAPI {
*/
@Nonnull
public static List<LocalHead> getLocalHeads() {
List<LocalHead> result = new ArrayList<>();
for (String entry : HeadDB.getInstance().getPlayerData().getEntries()) {
OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(entry));
result.add(new LocalHead(player.getUniqueId()).name(player.getName()));
}
return result;
return HeadDB.getInstance().getPlayerData().getEntries().stream()
.map(entry -> Bukkit.getOfflinePlayer(UUID.fromString(entry)))
.map(player -> new LocalHead(player.getUniqueId()).name(player.getName()))
.collect(Collectors.toList());
}
}

Datei anzeigen

@ -1,16 +1,16 @@
package tsp.headdb.event;
package tsp.headdb.api.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import tsp.headdb.api.Head;
import tsp.headdb.database.Category;
import tsp.headdb.database.HeadDatabase;
import tsp.headdb.implementation.Head;
import tsp.headdb.implementation.Category;
import tsp.headdb.implementation.HeadDatabase;
import java.util.List;
import java.util.Map;
/**
* This event is called AFTER a {@link tsp.headdb.database.HeadDatabase} updates.
* This event is called AFTER a {@link HeadDatabase} updates.
* The event is called asynchronously and can not be cancelled.
*
* @author TheSilentPro

Datei anzeigen

@ -1,10 +1,10 @@
package tsp.headdb.event;
package tsp.headdb.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import tsp.headdb.api.Head;
import tsp.headdb.implementation.Head;
/**
* This event is called when a player purchases a {@link Head}

Datei anzeigen

@ -1,175 +0,0 @@
package tsp.headdb.command;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import tsp.headdb.HeadDB;
import tsp.headdb.api.Head;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Localization;
import tsp.headdb.util.Utils;
import java.util.concurrent.TimeUnit;
// TODO: Cleaner way to handle this command
public class CommandHeadDB implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String s, String[] args) {
Localization localization = HeadDB.getInstance().getLocalization();
if (args.length == 0) {
if (!sender.hasPermission("headdb.open")) {
Utils.sendMessage(sender, localization.getMessage("noPermission"));
return true;
}
if (!(sender instanceof Player)) {
Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
return true;
}
Player player = (Player) sender;
Utils.sendMessage(player, localization.getMessage("databaseOpen"));
HeadAPI.openDatabase(player);
return true;
}
String sub = args[0];
if (sub.equalsIgnoreCase("info") || sub.equalsIgnoreCase("i")) {
// These should not be customizable
Utils.sendMessage(sender, "&7Running &cHeadDB - " + HeadDB.getInstance().getDescription().getVersion());
Utils.sendMessage(sender, "&7Created by &c" + HeadDB.getInstance().getDescription().getAuthors());
Utils.sendMessage(sender, "&7There are currently &c" + HeadAPI.getHeads().size() + " &7heads in the database.");
return true;
}
if (sub.equalsIgnoreCase("reload") || sub.equalsIgnoreCase("r")) {
if (!sender.hasPermission("headdb.reload")) {
Utils.sendMessage(sender, localization.getMessage("noPermission"));
return true;
}
HeadDB.getInstance().getLocalization().load();
Utils.sendMessage(sender, localization.getMessage("reloadMessages"));
return true;
}
if (sub.equalsIgnoreCase("search") || sub.equalsIgnoreCase("s")) {
if (!sender.hasPermission("headdb.search")) {
Utils.sendMessage(sender, localization.getMessage("noPermission"));
return true;
}
if (!(sender instanceof Player)) {
Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
return true;
}
Player player = (Player) sender;
if (args.length < 2) {
Utils.sendMessage(player, "&c/hdb search <name>");
return true;
}
StringBuilder builder = new StringBuilder();
for (int i = 1; i < args.length; i++) {
builder.append(args[i]);
if (i != args.length - 1) {
builder.append(" ");
}
}
String name = builder.toString();
Utils.sendMessage(sender, "&7Searching for &e" + name);
HeadAPI.openSearchDatabase(player, name);
return true;
}
if (sub.equalsIgnoreCase("tagsearch") || sub.equalsIgnoreCase("ts")) {
if (!sender.hasPermission("headdb.tagsearch")) {
Utils.sendMessage(sender, localization.getMessage("noPermission"));
return true;
}
if (args.length < 2) {
Utils.sendMessage(sender, "&c/hdb tagsearch <tag>");
return true;
}
if (!(sender instanceof Player)) {
Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
return true;
}
Player player = (Player) sender;
String tag = args[1];
Utils.sendMessage(sender, "&7Searching for heads with tag &e" + tag);
HeadAPI.openTagSearchDatabase(player, tag);
return true;
}
if (sub.equalsIgnoreCase("give") || sub.equalsIgnoreCase("g")) {
if (!sender.hasPermission("headdb.give")) {
Utils.sendMessage(sender, localization.getMessage("noPermission"));
return true;
}
if (args.length < 3) {
Utils.sendMessage(sender, "&c/hdb give <id> <player> &6[amount]");
return true;
}
try {
int id = Integer.parseInt(args[1]);
Player target = Bukkit.getPlayer(args[2]);
if (target == null) {
Utils.sendMessage(sender, localization.getMessage("invalidPlayer"));
return true;
}
int amount = 1;
if (args.length > 3) {
amount = Integer.parseInt(args[3]);
}
Head head = HeadAPI.getHeadByID(id);
if (head == null) {
Utils.sendMessage(sender, "&cCould not find head with id &e" + id);
return true;
}
ItemStack item = head.getMenuItem();
item.setAmount(amount);
target.getInventory().addItem(item);
Utils.sendMessage(sender, "&7Gave &6" + target.getName() + " &ex" + amount + " " + head.getName());
return true;
} catch (NumberFormatException nfe) {
Utils.sendMessage(sender, "&cID/Amount must be a number!");
return true;
}
}
if (sub.equalsIgnoreCase("update") || sub.equalsIgnoreCase("u")) {
if (!sender.hasPermission("headdb.update")) {
Utils.sendMessage(sender, "&cNo permission!");
return true;
}
Utils.sendMessage(sender, "&7Updating...");
long start = System.currentTimeMillis();
HeadAPI.getDatabase().updateAsync(heads -> {
Utils.sendMessage(sender, "&7Done! Took: &a" + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start) + " &7seconds");
Utils.sendMessage(sender, "&7There are &a" + HeadAPI.getHeads().size() + " &7heads in the database!");
});
return true;
}
Utils.sendMessage(sender, " ");
Utils.sendMessage(sender, "&c&lHeadDB &c- &5Commands");
Utils.sendMessage(sender, "&7&oParameters:&c command &9(aliases)&c arguments... &7- Description");
Utils.sendMessage(sender, "&7 > &c/hdb &7- Opens the database");
Utils.sendMessage(sender, "&7 > &c/hdb info &9(i) &7- Plugin Information");
Utils.sendMessage(sender, "&7 > &c/hdb reload &9(r) &7- Reloads the messages file");
Utils.sendMessage(sender, "&7 > &c/hdb search &9(s) &c<name> &7- Search for heads matching a name");
Utils.sendMessage(sender, "&7 > &c/hdb tagsearch &9(ts) &c<tag> &7- Search for heads matching a tag");
Utils.sendMessage(sender, "&7 > &c/hdb update &9(u) &7- Forcefully update the database");
Utils.sendMessage(sender, "&7 > &c/hdb give &9(g) &c<id> <player> &6[amount] &7- Give player a head");
Utils.sendMessage(sender, " ");
return true;
}
}

Datei anzeigen

@ -0,0 +1,53 @@
package tsp.headdb.command;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.implementation.Head;
import tsp.headdb.util.Utils;
public class GiveCommand implements HeadSubCommand {
@Override
public void handle(CommandSender sender, String[] args) {
if (!sender.hasPermission("headdb.give")) {
Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
return;
}
if (args.length < 3) {
Utils.sendMessage(sender, "&c/hdb give <id> <player> &6[amount]");
return;
}
try {
int id = Integer.parseInt(args[1]);
Player target = Bukkit.getPlayer(args[2]);
if (target == null) {
Utils.sendMessage(sender, getLocalization().getMessage("invalidPlayer"));
return;
}
int amount = 1;
if (args.length > 3) {
amount = Integer.parseInt(args[3]);
}
Head head = HeadAPI.getHeadByID(id);
if (head == null) {
Utils.sendMessage(sender, "&cCould not find head with id &e" + id);
return;
}
ItemStack item = head.getMenuItem();
item.setAmount(amount);
target.getInventory().addItem(item);
Utils.sendMessage(sender, "&7Gave &6" + target.getName() + " &ex" + amount + " " + head.getName());
} catch (NumberFormatException nfe) {
Utils.sendMessage(sender, "&cID/Amount must be a number!");
}
}
}

Datei anzeigen

@ -0,0 +1,68 @@
package tsp.headdb.command;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import tsp.headdb.HeadDB;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Localization;
import tsp.headdb.util.Utils;
public class HeadDBCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String s, String[] args) {
Localization localization = HeadDB.getInstance().getLocalization();
if (args.length == 0) {
if (!sender.hasPermission("headdb.open")) {
Utils.sendMessage(sender, localization.getMessage("noPermission"));
return true;
}
if (!(sender instanceof Player)) {
Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
return true;
}
Player player = (Player) sender;
Utils.sendMessage(player, localization.getMessage("databaseOpen"));
HeadAPI.openDatabase(player);
return true;
}
String sub = args[0];
HeadSubCommand subCommand = null;
if (sub.equalsIgnoreCase("info") || sub.equalsIgnoreCase("i")) {
subCommand = new InfoCommand();
} else if (sub.equalsIgnoreCase("reload") || sub.equalsIgnoreCase("r")) {
subCommand = new ReloadCommand();
} else if (sub.equalsIgnoreCase("search") || sub.equalsIgnoreCase("s")) {
subCommand = new SearchCommand();
} else if (sub.equalsIgnoreCase("tagsearch") || sub.equalsIgnoreCase("ts")) {
subCommand = new TagSearchCommand();
} else if (sub.equalsIgnoreCase("give") || sub.equalsIgnoreCase("g")) {
subCommand = new GiveCommand();
} else if (sub.equalsIgnoreCase("update") || sub.equalsIgnoreCase("u")) {
subCommand = new UpdateCommand();
}
if (subCommand != null) {
subCommand.handle(sender, args);
return true;
}
Utils.sendMessage(sender, " ");
Utils.sendMessage(sender, "&c&lHeadDB &c- &5Commands");
Utils.sendMessage(sender, "&7&oParameters:&c command &9(aliases)&c arguments... &7- Description");
Utils.sendMessage(sender, "&7 > &c/hdb &7- Opens the database");
Utils.sendMessage(sender, "&7 > &c/hdb info &9(i) &7- Plugin Information");
Utils.sendMessage(sender, "&7 > &c/hdb reload &9(r) &7- Reloads the messages file");
Utils.sendMessage(sender, "&7 > &c/hdb search &9(s) &c<name> &7- Search for heads matching a name");
Utils.sendMessage(sender, "&7 > &c/hdb tagsearch &9(ts) &c<tag> &7- Search for heads matching a tag");
Utils.sendMessage(sender, "&7 > &c/hdb update &9(u) &7- Forcefully update the database");
Utils.sendMessage(sender, "&7 > &c/hdb give &9(g) &c<id> <player> &6[amount] &7- Give player a head");
Utils.sendMessage(sender, " ");
return true;
}
}

Datei anzeigen

@ -0,0 +1,21 @@
package tsp.headdb.command;
import org.bukkit.command.CommandSender;
import tsp.headdb.HeadDB;
import tsp.headdb.util.Localization;
/**
* An interface for a HeadDB sub-command
*
* @author TheSilentPro
* @since 4.0.0
*/
public interface HeadSubCommand {
void handle(CommandSender sender, String[] args);
default Localization getLocalization() {
return HeadDB.getInstance().getLocalization();
}
}

Datei anzeigen

@ -0,0 +1,18 @@
package tsp.headdb.command;
import org.bukkit.command.CommandSender;
import tsp.headdb.HeadDB;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Utils;
public class InfoCommand implements HeadSubCommand {
@Override
public void handle(CommandSender sender, String[] args) {
// These should not be customizable
Utils.sendMessage(sender, "&7Running &cHeadDB - " + HeadDB.getInstance().getDescription().getVersion());
Utils.sendMessage(sender, "&7Created by &c" + HeadDB.getInstance().getDescription().getAuthors());
Utils.sendMessage(sender, "&7There are currently &c" + HeadAPI.getHeads().size() + " &7heads in the database.");
}
}

Datei anzeigen

@ -0,0 +1,20 @@
package tsp.headdb.command;
import org.bukkit.command.CommandSender;
import tsp.headdb.HeadDB;
import tsp.headdb.util.Utils;
public class ReloadCommand implements HeadSubCommand {
@Override
public void handle(CommandSender sender, String[] args) {
if (!sender.hasPermission("headdb.reload")) {
Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
return;
}
HeadDB.getInstance().getLocalization().load();
Utils.sendMessage(sender, getLocalization().getMessage("reloadMessages"));
}
}

Datei anzeigen

@ -0,0 +1,40 @@
package tsp.headdb.command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Utils;
public class SearchCommand implements HeadSubCommand {
@Override
public void handle(CommandSender sender, String[] args) {
if (!sender.hasPermission("headdb.search")) {
Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
return;
}
if (!(sender instanceof Player)) {
Utils.sendMessage(sender, getLocalization().getMessage("onlyPlayers"));
return;
}
Player player = (Player) sender;
if (args.length < 2) {
Utils.sendMessage(player, "&c/hdb search <name>");
return;
}
StringBuilder builder = new StringBuilder();
for (int i = 1; i < args.length; i++) {
builder.append(args[i]);
if (i != args.length - 1) {
builder.append(" ");
}
}
String name = builder.toString();
Utils.sendMessage(sender, "&7Searching for &e" + name);
HeadAPI.openSearchDatabase(player, name);
return;
}
}

Datei anzeigen

@ -0,0 +1,34 @@
package tsp.headdb.command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Utils;
public class TagSearchCommand implements HeadSubCommand {
@Override
public void handle(CommandSender sender, String[] args) {
if (!sender.hasPermission("headdb.tagsearch")) {
Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
return;
}
if (args.length < 2) {
Utils.sendMessage(sender, "&c/hdb tagsearch <tag>");
return;
}
if (!(sender instanceof Player)) {
Utils.sendMessage(sender, getLocalization().getMessage("onlyPlayers"));
return;
}
Player player = (Player) sender;
String tag = args[1];
Utils.sendMessage(sender, "&7Searching for heads with tag &e" + tag);
HeadAPI.openTagSearchDatabase(player, tag);
return;
}
}

Datei anzeigen

@ -0,0 +1,26 @@
package tsp.headdb.command;
import org.bukkit.command.CommandSender;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Utils;
import java.util.concurrent.TimeUnit;
public class UpdateCommand implements HeadSubCommand {
@Override
public void handle(CommandSender sender, String[] args) {
if (!sender.hasPermission("headdb.update")) {
Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
return;
}
Utils.sendMessage(sender, "&7Updating...");
long start = System.currentTimeMillis();
HeadAPI.getDatabase().update(heads -> {
Utils.sendMessage(sender, "&7Done! Took: &a" + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start) + " &7seconds");
Utils.sendMessage(sender, "&7There are &a" + HeadAPI.getHeads().size() + " &7heads in the database!");
});
}
}

Datei anzeigen

@ -0,0 +1,48 @@
package tsp.headdb.economy;
import org.bukkit.entity.Player;
import java.math.BigDecimal;
import java.util.function.Consumer;
/**
* An interface for generalizing Economy Provider's
*
* @author TheSilentPro
* @since 4.0.0
* @see VaultProvider
* @see TreasuryProvider
*/
public interface BasicEconomyProvider {
/**
* Retrieve if the player can purchase a head using this economy provider
*
* @param player The player
* @param cost The cost
* @param result If the player has enough to purchase
*/
default void canPurchase(Player player, BigDecimal cost, Consumer<Boolean> result) {
result.accept(true);
}
/**
* Charge the player a specific amount using this economy provider
*
* @param player The player
* @param amount The amount
* @param result If the transaction was successful
*/
default void charge(Player player, BigDecimal amount, Consumer<Boolean> result) {
result.accept(true);
}
/**
* Convenience method for initializing economy
*
* @see VaultProvider#initProvider()
* @see TreasuryProvider#initProvider()
*/
void initProvider();
}

Datei anzeigen

@ -1,21 +0,0 @@
package tsp.headdb.economy;
import org.bukkit.entity.Player;
import java.math.BigDecimal;
public interface HEconomyProvider {
default boolean canPurchase(Player player, BigDecimal cost) {
return true;
}
default void charge(Player player, BigDecimal amount) {
}
default void initProvider() {
}
}

Datei anzeigen

@ -0,0 +1,99 @@
package tsp.headdb.economy;
import me.lokka30.treasury.api.common.service.Service;
import me.lokka30.treasury.api.common.service.ServiceRegistry;
import me.lokka30.treasury.api.economy.EconomyProvider;
import me.lokka30.treasury.api.economy.account.PlayerAccount;
import me.lokka30.treasury.api.economy.currency.Currency;
import me.lokka30.treasury.api.economy.response.EconomyException;
import me.lokka30.treasury.api.economy.response.EconomySubscriber;
import me.lokka30.treasury.api.economy.transaction.EconomyTransactionInitiator;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import tsp.headdb.HeadDB;
import tsp.headdb.util.Log;
import java.math.BigDecimal;
import java.util.Optional;
import java.util.function.Consumer;
/**
* A {@link BasicEconomyProvider} for Treasury
*
* @author TheSilentPro
* @since 4.0.0
*/
public class TreasuryProvider implements BasicEconomyProvider {
private EconomyProvider provider;
private Currency currency;
@Override
public void canPurchase(Player player, BigDecimal cost, Consumer<Boolean> result) {
EconomySubscriber
.<Boolean>asFuture(s -> provider.hasPlayerAccount(player.getUniqueId(), s))
.thenCompose(val -> {
if (val) {
return EconomySubscriber.<PlayerAccount>asFuture(s -> provider.retrievePlayerAccount(player.getUniqueId(), s));
} else {
return EconomySubscriber.<PlayerAccount>asFuture(s -> provider.createPlayerAccount(player.getUniqueId(), s));
}
})
.thenCompose(account -> EconomySubscriber.<BigDecimal>asFuture(s -> account.retrieveBalance(currency, s)))
.whenComplete((bal, ex) -> {
result.accept(bal.compareTo(cost) >= 0);
});
}
@Override
public void charge(Player player, BigDecimal amount, Consumer<Boolean> result) {
EconomySubscriber
.<Boolean>asFuture(s -> provider.hasPlayerAccount(player.getUniqueId(), s))
.thenCompose(val -> {
if (val) {
return EconomySubscriber.<PlayerAccount>asFuture(s -> provider.retrievePlayerAccount(player.getUniqueId(), s));
} else {
return EconomySubscriber.<PlayerAccount>asFuture(s -> provider.createPlayerAccount(player.getUniqueId(), s));
}
}).whenComplete((account, ex) -> {
account.withdrawBalance(
amount,
EconomyTransactionInitiator.createInitiator(EconomyTransactionInitiator.Type.PLUGIN, "HeadDB"),
currency,
new EconomySubscriber<BigDecimal>() {
@Override
public void succeed(@NotNull BigDecimal bigDecimal) {
result.accept(true);
}
@Override
public void fail(@NotNull EconomyException exception) {
result.accept(false);
exception.printStackTrace();
}
});
});
}
@Override
public void initProvider() {
Optional<Service<EconomyProvider>> service = ServiceRegistry.INSTANCE.serviceFor(EconomyProvider.class);
if(!service.isPresent()) {
Log.error("Unable to find a supported economy plugin for Treasury!");
return;
}
provider = service.get().get();
String rawCurrency = HeadDB.getInstance().getConfig().getString("economy.currency");
if (rawCurrency == null || rawCurrency.isEmpty()) {
currency = provider.getPrimaryCurrency();
} else {
currency = provider.getCurrencies().stream()
.filter(currency -> currency.getIdentifier().equalsIgnoreCase(rawCurrency))
.findFirst().get();
}
}
}

Datei anzeigen

@ -5,21 +5,29 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import tsp.headdb.util.Log;
import tsp.headdb.util.Utils;
import java.math.BigDecimal;
import java.util.function.Consumer;
public class VaultProvider implements HEconomyProvider {
/**
* A {@link BasicEconomyProvider} for Vault
*
* @author TheSilentPro
* @since 4.0.0
*/
public class VaultProvider implements BasicEconomyProvider {
private Economy economy;
@Override
public boolean canPurchase(Player player, BigDecimal cost) {
return economy.has(player, cost.doubleValue());
public void canPurchase(Player player, BigDecimal cost, Consumer<Boolean> result) {
Utils.async(t -> result.accept(economy.has(player, cost.doubleValue())));
}
@Override
public void charge(Player player, BigDecimal amount) {
economy.withdrawPlayer(player, amount.doubleValue());
public void charge(Player player, BigDecimal amount, Consumer<Boolean> result) {
Utils.async(t -> result.accept(economy.withdrawPlayer(player, amount.doubleValue()).transactionSuccess()));
}
public void initProvider() {

Datei anzeigen

@ -1,10 +1,10 @@
package tsp.headdb.database;
package tsp.headdb.implementation;
import org.bukkit.ChatColor;
import org.bukkit.inventory.ItemStack;
import tsp.headdb.api.Head;
import tsp.headdb.api.HeadAPI;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
@ -45,15 +45,24 @@ public enum Category {
return location;
}
/**
* Retrieve the first valid head from a category
*
* @return First valid head
*/
public ItemStack getItem() {
if (item.containsKey(this)) {
return item.get(this).getMenuItem();
}
item.put(this, HeadAPI.getHeads(this).get(0));
return getItem();
return HeadAPI.getHeads(this).stream()
.filter(head -> head != null)
.findFirst().get().getMenuItem();
}
/**
* Retrieve a {@link Category} by name
*
* @param name The name
* @return The category if it exists. Else it returns null
*/
@Nullable
public static Category getByName(String name) {
for (Category category : cache) {
if (category.getName().equalsIgnoreCase(name)) {

Datei anzeigen

@ -1,4 +1,4 @@
package tsp.headdb.database;
package tsp.headdb.implementation;
import tsp.headdb.HeadDB;
import tsp.headdb.api.HeadAPI;
@ -9,7 +9,7 @@ public class DatabaseUpdateTask implements Runnable {
@Override
public void run() {
HeadDB.getInstance().getPlayerData().save();
HeadAPI.getDatabase().updateAsync(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!"));
HeadAPI.getDatabase().update(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!"));
}
}

Datei anzeigen

@ -1,14 +1,11 @@
package tsp.headdb.api;
package tsp.headdb.implementation;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import tsp.headdb.HeadDB;
import tsp.headdb.database.Category;
import tsp.headdb.util.Log;
import tsp.headdb.util.Utils;

Datei anzeigen

@ -1,4 +1,4 @@
package tsp.headdb.database;
package tsp.headdb.implementation;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -7,8 +7,7 @@ import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import tsp.headdb.api.Head;
import tsp.headdb.event.DatabaseUpdateEvent;
import tsp.headdb.api.event.DatabaseUpdateEvent;
import tsp.headdb.util.Log;
import tsp.headdb.util.Utils;
@ -18,6 +17,7 @@ import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -117,7 +117,7 @@ public class HeadDatabase {
}
public List<Head> getHeads(Category category) {
return HEADS.get(category);
return Collections.unmodifiableList(HEADS.get(category));
}
/**
@ -129,7 +129,7 @@ public class HeadDatabase {
public List<Head> getHeads() {
if (HEADS.isEmpty() || isLastUpdateOld()) {
// Technically this should never be reached due to the update task in the main class.
updateAsync(result -> {
update(result -> {
if (result != null) {
for (Category category : result.keySet()) {
HEADS.put(category, result.get(category));
@ -145,7 +145,7 @@ public class HeadDatabase {
return heads;
}
public void getHeadsNoCacheAsync(Consumer<Map<Category, List<Head>>> resultSet) {
public void getHeadsNoCache(Consumer<Map<Category, List<Head>>> resultSet) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, task -> {
Log.debug("[" + plugin.getName() + "] Updating database... ");
Map<Category, List<Head>> result = new HashMap<>();
@ -207,8 +207,8 @@ public class HeadDatabase {
});
}
public void updateAsync(Consumer<Map<Category, List<Head>>> result) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, task -> getHeadsNoCacheAsync(heads -> {
public void update(Consumer<Map<Category, List<Head>>> result) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, task -> getHeadsNoCache(heads -> {
if (heads == null) {
Log.error("[" + plugin.getName() + "] Failed to update database! Check above for any errors.");
result.accept(null);

Datei anzeigen

@ -1,11 +1,10 @@
package tsp.headdb.api;
package tsp.headdb.implementation;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import tsp.headdb.database.Category;
import tsp.headdb.util.Utils;
import java.util.ArrayList;

Datei anzeigen

@ -9,22 +9,21 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import tsp.headdb.HeadDB;
import tsp.headdb.api.Head;
import tsp.headdb.implementation.Head;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.api.LocalHead;
import tsp.headdb.database.Category;
import tsp.headdb.economy.HEconomyProvider;
import tsp.headdb.event.PlayerHeadPurchaseEvent;
import tsp.headdb.implementation.LocalHead;
import tsp.headdb.implementation.Category;
import tsp.headdb.economy.BasicEconomyProvider;
import tsp.headdb.api.event.PlayerHeadPurchaseEvent;
import tsp.headdb.util.Localization;
import tsp.headdb.util.Utils;
import net.milkbowl.vault.economy.Economy;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* Class for handling the "dirty" work
@ -308,49 +307,62 @@ public class InventoryUtils {
return HeadDB.getInstance().getConfig().getDouble("economy.cost." + category);
}
public static boolean processPayment(Player player, int amount, String category, String description) {
HEconomyProvider economyProvider = HeadDB.getInstance().getEconomyProvider();
public static void processPayment(Player player, int amount, String category, String description, Consumer<Boolean> result) {
Utils.async(task -> {
BasicEconomyProvider economyProvider = HeadDB.getInstance().getEconomyProvider();
// If economy is disabled or no plugin is present, the item is free.
// Don't mention receiving it for free in this case, since it is always free.
if (economyProvider == null) {
Utils.sendMessage(player, String.format(localization.getMessage("noEconomy"), amount, description));
Utils.playSound(player, "noEconomy");
return true;
}
BigDecimal cost = BigDecimal.valueOf(getCategoryCost(player, category) * amount);
// If the cost is higher than zero, attempt to charge for it.
if (cost.compareTo(BigDecimal.ZERO) > 0) {
if (economyProvider.canPurchase(player, cost)) {
economyProvider.charge(player, cost);
Utils.sendMessage(player, String.format(localization.getMessage("purchasedHead"), amount, description, cost));
Utils.playSound(player, "paid");
return true;
// If economy is disabled or no plugin is present, the item is free.
// Don't mention receiving it for free in this case, since it is always free.
if (economyProvider == null) {
Utils.sendMessage(player, String.format(localization.getMessage("noEconomy"), amount, description));
Utils.playSound(player, "noEconomy");
result.accept(true);
return;
}
Utils.sendMessage(player, String.format(localization.getMessage("notEnoughMoney"), amount, description));
Utils.playSound(player, "unavailable");
return false;
}
BigDecimal cost = BigDecimal.valueOf(getCategoryCost(player, category) * amount);
// Otherwise, the item is free.
Utils.sendMessage(player, String.format(localization.getMessage("free"), amount, description));
Utils.playSound(player, "free");
return true;
// If the cost is higher than zero, attempt to charge for it.
if (cost.compareTo(BigDecimal.ZERO) > 0) {
economyProvider.canPurchase(player, cost, paymentResult -> {
if (paymentResult) {
economyProvider.charge(player, cost, chargeResult -> {
if (chargeResult) {
Utils.sendMessage(player, String.format(localization.getMessage("purchasedHead"), amount, description, cost));
Utils.playSound(player, "paid");
result.accept(true);
return;
}
});
}
});
Utils.sendMessage(player, String.format(localization.getMessage("notEnoughMoney"), amount, description));
Utils.playSound(player, "unavailable");
result.accept(false);
return;
}
// Otherwise, the item is free.
Utils.sendMessage(player, String.format(localization.getMessage("free"), amount, description));
Utils.playSound(player, "free");
result.accept(true);
});
}
public static void purchaseHead(Player player, Head head, int amount, String category, String description) {
if (!processPayment(player, amount, category, description)) return;
PlayerHeadPurchaseEvent event = new PlayerHeadPurchaseEvent(player, head, getCategoryCost(player, category));
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
ItemStack item = head.getMenuItem();
item.setAmount(amount);
player.getInventory().addItem(item);
}
Utils.sendMessage(player, "&7Purchasing &e" + amount + "x " + head.getName() + "&7. Please wait...");
processPayment(player, amount, category, description, result -> {
if (result) {
PlayerHeadPurchaseEvent event = new PlayerHeadPurchaseEvent(player, head, getCategoryCost(player, category));
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
ItemStack item = head.getMenuItem();
item.setAmount(amount);
player.getInventory().addItem(item);
}
}
});
}
private static String replace(String message, int size, String category, String search, Player player) {

Datei anzeigen

@ -12,7 +12,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import tsp.headdb.HeadDB;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.database.Category;
import tsp.headdb.implementation.Category;
import tsp.headdb.inventory.InventoryUtils;
import tsp.headdb.util.Utils;

Datei anzeigen

@ -7,6 +7,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import tsp.headdb.HeadDB;
import java.io.BufferedReader;
@ -22,6 +23,10 @@ public class Utils {
private static final FileConfiguration config = HeadDB.getInstance().getConfig();
public static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}");
public static void async(Consumer<BukkitTask> task) {
Bukkit.getScheduler().runTaskAsynchronously(HeadDB.getInstance(), task);
}
/**
* Retrieve the latest release from spigot
*

Datei anzeigen

@ -11,8 +11,12 @@ requireCategoryPermission: false
# Economy options
economy:
enable: false
# Supported: VAULT
# Supported: VAULT, TREASURY
provider: "VAULT"
# Providers like treasury support multiple currencies
# Set the ID of the one used for head purchasing below.
# Leave empty to use the primary currency or if the provider does not support multiple currencies
currency: ''
cost:
alphabet: 100
animals: 100