Last active
February 10, 2021 21:47
-
-
Save Sxtanna/af4f01d21cd5c35ce047a9e64a0dab48 to your computer and use it in GitHub Desktop.
Vault Economy Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.jetbrains.annotations.Contract; | |
import org.jetbrains.annotations.NotNull; | |
import org.bukkit.Bukkit; | |
import org.bukkit.OfflinePlayer; | |
import org.bukkit.plugin.RegisteredServiceProvider; | |
import java.math.BigDecimal; | |
import java.util.Optional; | |
import java.util.function.Consumer; | |
/** | |
* Drag and Drop Vault Economy Wrapper | |
* | |
* @see Response | |
*/ | |
public final class Economy | |
{ | |
/** | |
* Represents a transaction response from Vault | |
* | |
* @see Response#getResult() | |
* @see Response#getReason() | |
*/ | |
public static final class Response | |
{ | |
/** | |
* Represents whether the result of the transaction was passing or failing | |
*/ | |
public enum Result | |
{ | |
PASS, | |
FAIL, | |
} | |
@NotNull | |
private final Result result; | |
@NotNull | |
private final String reason; | |
@Contract(pure = true) | |
private Response(@NotNull final Result result, @NotNull final String reason) | |
{ | |
this.result = result; | |
this.reason = reason; | |
} | |
/** | |
* @return Whether the transaction passed or failed | |
*/ | |
@Contract(pure = true) | |
public @NotNull Result getResult() | |
{ | |
return result; | |
} | |
/** | |
* @return The reason the transaction failed, if it failed... | |
*/ | |
@Contract(pure = true) | |
public @NotNull String getReason() | |
{ | |
return reason; | |
} | |
/** | |
* @return true if this transaction was successful, false otherwise | |
*/ | |
@Contract(pure = true) | |
public boolean isPassing() | |
{ | |
return getResult() == Result.PASS; | |
} | |
/** | |
* @return true if this transaction failed, false otherwise | |
*/ | |
@Contract(pure = true) | |
public boolean isFailing() | |
{ | |
return getResult() == Result.FAIL; | |
} | |
/** | |
* Convenience function for handling the state of this response | |
* | |
* @param passing What to do if this transaction was successful | |
* @param failing What to do if this transaction failed | |
*/ | |
public void handle(@NotNull final Runnable passing, @NotNull final Consumer<String> failing) | |
{ | |
// switch over the possible results | |
switch (getResult()) | |
{ | |
case PASS: | |
// run the passing runnable when this is a passing response | |
passing.run(); | |
break; | |
case FAIL: | |
// provide the reason to the failing consumer when this is a failing response | |
failing.accept(getReason()); | |
break; | |
default: | |
// throw an exception when no applicable case is found (should not happen) | |
throw new UnsupportedOperationException(String.format("unexpected response result: %s?", getResult())); | |
} | |
} | |
/** | |
* Creates a new response denoting a successful transaction | |
* | |
* @return The new response holding {@link Result#PASS} | |
*/ | |
@Contract(value = " -> new", pure = true) | |
public static @NotNull Response passing() | |
{ | |
return new Response(Result.PASS, ""); /* todo: this could probably be a single instance, like Optional.empty()*/ | |
} | |
/** | |
* Creates a new response denoting a failing transaction | |
* | |
* @param reason The reason the transaction failed | |
* @return The new response holding {@link Result#FAIL} and a Reason | |
*/ | |
@Contract(value = "_ -> new", pure = true) | |
public static @NotNull Response failing(@NotNull final String reason) | |
{ | |
return new Response(Result.FAIL, reason); | |
} | |
} | |
/** | |
* Attempts to retrieve the current balance of the supplied {@link OfflinePlayer} | |
* | |
* @param player The player whose balance to retrieve. | |
* @return An {@link Optional} containing the player's balance if available, otherwise empty. | |
*/ | |
public static @NotNull Optional<BigDecimal> get(@NotNull final OfflinePlayer player) | |
{ | |
try | |
{ | |
// attempt to retrieve the registered provider for vault's economy, will either return null or throw NCDFE | |
final RegisteredServiceProvider<net.milkbowl.vault.economy.Economy> registration = Bukkit.getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); | |
if (registration == null) | |
{ | |
// this will be null when there is no economy plugin, simply return an empty optional | |
return Optional.empty(); | |
} | |
// wrap the result of their current balance in a big decimal, because using floating point values for money is DUMB | |
return Optional.of(BigDecimal.valueOf(registration.getProvider().getBalance(player))); | |
} | |
catch (final NoClassDefFoundError ignored) | |
{ | |
// this error will be thrown if vault is not loaded on this server, simply return an empty optional | |
return Optional.empty(); | |
} | |
} | |
/** | |
* Attempts to take the supplied amount of money from the player's balance. (withdraw) | |
* | |
* @param player The player whose balance to take from | |
* @param amount The amount of money to take from them | |
* @return A response denoting the outcome of this withdrawal attempt | |
*/ | |
public static @NotNull Response take(@NotNull final OfflinePlayer player, @NotNull final BigDecimal amount) | |
{ | |
try | |
{ | |
// attempt to retrieve the registered provider for vault's economy, will either return null or throw NCDFE | |
final RegisteredServiceProvider<net.milkbowl.vault.economy.Economy> registration = Bukkit.getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); | |
if (registration == null) | |
{ | |
// this will be null when there is no economy plugin, simply return an "no economy" response | |
return Response.failing("no economy"); | |
} | |
// attempt to withdraw the double value of the provided BigDecimal amount | |
final net.milkbowl.vault.economy.EconomyResponse response = registration.getProvider().withdrawPlayer(player, amount.doubleValue()); | |
// return either a passing response, or a failing response containing the error message | |
return response.transactionSuccess() ? Response.passing() : Response.failing(response.errorMessage); | |
} | |
catch (final NoClassDefFoundError error) | |
{ | |
// return a failing response with the NCDFE message (probably not ideal? maybe just say "no vault") | |
return Response.failing(String.format("withdraw failed: %s", error.getMessage())); | |
} | |
} | |
/** | |
* Attempts to give the supplied amount of money to the player. (deposit) | |
* | |
* @param player The player whose balance to give to | |
* @param amount The amount of money to give them | |
* @return A response denoting the outcome of this deposit attempt | |
*/ | |
public static @NotNull Response give(@NotNull final OfflinePlayer player, @NotNull final BigDecimal amount) | |
{ | |
try | |
{ | |
// attempt to retrieve the registered provider for vault's economy, will either return null or throw NCDFE | |
final RegisteredServiceProvider<net.milkbowl.vault.economy.Economy> registration = Bukkit.getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); | |
if (registration == null) | |
{ | |
// this will be null when there is no economy plugin, simply return an "no economy" response | |
return Response.failing("no economy"); | |
} | |
// attempt to deposit the double value of the provided BigDecimal amount | |
final net.milkbowl.vault.economy.EconomyResponse response = registration.getProvider().depositPlayer(player, amount.doubleValue()); | |
// return either a passing response, or a failing response containing the error message | |
return response.transactionSuccess() ? Response.passing() : Response.failing(response.errorMessage); | |
} | |
catch (final NoClassDefFoundError error) | |
{ | |
// return a failing response with the NCDFE message (probably not ideal? maybe just say "no vault") | |
return Response.failing(String.format("deposit failed: %s", error.getMessage())); | |
} | |
} | |
} |
Example of this resource's usage
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public final class EconomyExample
{
public static final class Product
{
@NotNull
private final String name;
@NotNull
private final BigDecimal cost;
@NotNull
private final ItemStack item;
@Contract(pure = true)
public Product(@NotNull final String name, @NotNull final BigDecimal cost, @NotNull final ItemStack item)
{
this.name = name;
this.cost = cost;
this.item = item;
}
@Contract(pure = true)
public @NotNull String getName()
{
return name;
}
@Contract(pure = true)
public @NotNull BigDecimal getCost()
{
return cost;
}
@Contract(pure = true)
public @NotNull ItemStack getItem()
{
return item;
}
public @NotNull BigDecimal getCostAtAmount(final int amount)
{
final int count = getItem().getAmount();
final BigDecimal price = getCost().divide(BigDecimal.valueOf(count), BigDecimal.ROUND_HALF_EVEN);
return price.multiply(BigDecimal.valueOf(amount));
}
public @NotNull ItemStack getItemAtAmount(final int amount)
{
final ItemStack stack = getItem().clone();
stack.setAmount(amount);
return stack;
}
@Override
public String toString()
{
return String.format("Product['%s'{%s}: %s]", name, cost, item);
}
@Override
public boolean equals(final Object o)
{
if (this == o)
{
return true;
}
if (!(o instanceof Product))
{
return false;
}
final Product that = (Product) o;
return this.getName().equals(that.getName()) &&
this.getCost().equals(that.getCost()) &&
this.getItem().equals(that.getItem());
}
@Override
public int hashCode()
{
return Objects.hash(this.getName(),
this.getCost(),
this.getItem());
}
}
public static void main(String[] args)
{
final List<Product> products = Arrays.asList(
new Product("Stone x64", BigDecimal.valueOf(100), new ItemStack(Material.STONE, 64)),
new Product("Grass x32", BigDecimal.valueOf(300), new ItemStack(Material.GRASS_BLOCK, 32))
);
final Player player = Bukkit.getOnlinePlayers().iterator().next();
Economy.give(player, BigDecimal.valueOf(350)).handle(() -> {}, reason -> {
// imagine not being able to have $350
});
for (final Product product : products)
{
final Economy.Response response = Economy.take(player, product.getCost());
switch (response.getResult())
{
case FAIL:
player.sendMessage(String.format("Failed to purchase %s for $%s: %s", product.getName(), product.getCost().toPlainString(), response.getReason()));
break;
case PASS:
player.sendMessage(String.format("Successfully purchased %s for $%s", product.getName(), product.getCost().toPlainString()));
final Map<Integer, ItemStack> failed = player.getInventory().addItem(product.getItem());
if (failed.isEmpty())
{
return;
}
final ItemStack remain = failed.get(0);
final BigDecimal refund = product.getCostAtAmount(remain.getAmount());
if (refund.compareTo(BigDecimal.ZERO) <= 0)
{
return;
}
Economy.give(player, refund);
player.sendMessage(String.format("You have been refunded $%s because your inventory could not hold x%d of the purchased items!", refund.toPlainString(), remain.getAmount()));
break;
}
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Plugin Description
Repository and Dependency
Gradle
Maven