diff --git a/pom.xml b/pom.xml
index 1550ddf..24780a7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,8 +23,8 @@
maven-compiler-plugin
3.8.1
-
- 11
+
+ 12
@@ -95,13 +95,21 @@
placeholderapi
https://repo.extendedclip.com/content/repositories/placeholderapi/
+
+ techscode
+ https://repo.techscode.com/repository/maven-releases/
+
+
+ rosewood-repo
+ https://repo.rosewooddev.io/repository/public/
+
com.artillexstudios.axapi
axapi
- 1.4.109
+ 1.4.136
compile
@@ -128,5 +136,90 @@
3.0.2
compile
+
+
+ me.aglerr.mobcoins
+ MobCoins
+ 1.1.3
+ ${project.basedir}/libs/TheOnly-MobCoins-1.1.3.jar
+ system
+
+
+ com.artillexstudios
+ AxQuestBoardAPI
+ 1
+ provided
+
+
+ com.github.Realizedd
+ TokenManager
+ 3.2.4
+ provided
+
+
+ *
+ *
+
+
+
+
+ me.swanis.mobcoins
+ MobCoins
+ 1.1.2
+ ${project.basedir}/libs/mobcoins-api-1.1.2-SNAPSHOT.jar
+ system
+
+
+ me.rivaldev.harvesterhoes
+ Main
+ LATEST
+ ${project.basedir}/libs/RivalHarvesterHoesAPI.jar
+ system
+
+
+ com.github.cryptomorin
+ kingdoms
+ LATEST
+ ${project.basedir}/libs/KingdomsX-1.16.14.1.jar
+ system
+
+
+ su.nightexpress.coinsengine
+ CoinsEngine
+ 2.1.1
+ ${project.basedir}/libs/CoinsEngine-2.1.1.jar
+ system
+
+
+ me.qKing12.RoyaleEconomy
+ RoyaleEconomy
+ 1.4.4
+ ${project.basedir}/libs/RoyaleEconomyAPI.jar
+ system
+
+
+ com.github.MilkBowl
+ VaultAPI
+ 1.7
+ provided
+
+
+ org.black_ixx
+ playerpoints
+ 3.2.6
+ provided
+
+
+ me.TechsCode
+ UltraEconomyAPI
+ 2.6.4
+ provided
+
+
+ de.rapha149.signgui
+ signgui
+ 2.3.2
+ compile
+
diff --git a/src/main/java/com/artillexstudios/axtrade/AxTrade.java b/src/main/java/com/artillexstudios/axtrade/AxTrade.java
index c27b2e8..33fb853 100644
--- a/src/main/java/com/artillexstudios/axtrade/AxTrade.java
+++ b/src/main/java/com/artillexstudios/axtrade/AxTrade.java
@@ -11,7 +11,11 @@ import com.artillexstudios.axapi.libs.boostedyaml.boostedyaml.settings.updater.U
import com.artillexstudios.axapi.utils.MessageUtils;
import com.artillexstudios.axapi.utils.StringUtils;
import com.artillexstudios.axtrade.commands.Commands;
+import com.artillexstudios.axtrade.hooks.HookManager;
+import com.artillexstudios.axtrade.listeners.PlayerInteractEntityListener;
+import com.artillexstudios.axtrade.listeners.TradeListeners;
import com.artillexstudios.axtrade.trade.TradeTicker;
+import com.artillexstudios.axtrade.utils.NumberUtils;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
@@ -22,6 +26,7 @@ public final class AxTrade extends AxPlugin {
public static Config CONFIG;
public static Config LANG;
public static Config GUIS;
+ public static Config HOOKS;
public static MessageUtils MESSAGEUTILS;
private static AxPlugin instance;
private static ThreadedQueue threadedQueue;
@@ -44,6 +49,7 @@ public final class AxTrade extends AxPlugin {
CONFIG = new Config(new File(getDataFolder(), "config.yml"), getResource("config.yml"), GeneralSettings.builder().setUseDefaults(false).build(), LoaderSettings.builder().setAutoUpdate(true).build(), DumperSettings.DEFAULT, UpdaterSettings.builder().setKeepAll(true).setVersioning(new BasicVersioning("version")).build());
GUIS = new Config(new File(getDataFolder(), "guis.yml"), getResource("guis.yml"), GeneralSettings.builder().setUseDefaults(false).build(), LoaderSettings.builder().setAutoUpdate(true).build(), DumperSettings.DEFAULT, UpdaterSettings.builder().setKeepAll(true).setVersioning(new BasicVersioning("version")).build());
LANG = new Config(new File(getDataFolder(), "lang.yml"), getResource("lang.yml"), GeneralSettings.builder().setUseDefaults(false).build(), LoaderSettings.builder().setAutoUpdate(true).build(), DumperSettings.DEFAULT, UpdaterSettings.builder().setKeepAll(true).setVersioning(new BasicVersioning("version")).build());
+ HOOKS = new Config(new File(getDataFolder(), "currencies.yml"), getResource("currencies.yml"), GeneralSettings.builder().setUseDefaults(false).build(), LoaderSettings.builder().setAutoUpdate(true).build(), DumperSettings.DEFAULT, UpdaterSettings.builder().setKeepAll(true).setVersioning(new BasicVersioning("version")).build());
MESSAGEUTILS = new MessageUtils(LANG.getBackingDocument(), "prefix", CONFIG.getBackingDocument());
@@ -51,10 +57,16 @@ public final class AxTrade extends AxPlugin {
BUKKITAUDIENCES = BukkitAudiences.create(this);
+ getServer().getPluginManager().registerEvents(new PlayerInteractEntityListener(), this);
+ getServer().getPluginManager().registerEvents(new TradeListeners(), this);
+
+ new HookManager().setupHooks();
+ NumberUtils.reload();
+
new TradeTicker().start();
Commands.registerCommand();
- Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("ffdd[AxTrade] Loaded plugin!"));
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("FFDD[AxTrade] Loaded plugin!"));
}
}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/commands/Commands.java b/src/main/java/com/artillexstudios/axtrade/commands/Commands.java
index 5a46e14..b5bdede 100644
--- a/src/main/java/com/artillexstudios/axtrade/commands/Commands.java
+++ b/src/main/java/com/artillexstudios/axtrade/commands/Commands.java
@@ -2,13 +2,18 @@ package com.artillexstudios.axtrade.commands;
import com.artillexstudios.axapi.utils.StringUtils;
import com.artillexstudios.axtrade.AxTrade;
+import com.artillexstudios.axtrade.hooks.HookManager;
+import com.artillexstudios.axtrade.request.Requests;
import com.artillexstudios.axtrade.trade.Trades;
+import com.artillexstudios.axtrade.utils.NumberUtils;
+import com.artillexstudios.axtrade.utils.SoundUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionDefault;
import org.jetbrains.annotations.NotNull;
import revxrsal.commands.annotation.DefaultFor;
+import revxrsal.commands.annotation.Optional;
import revxrsal.commands.annotation.Subcommand;
import revxrsal.commands.bukkit.BukkitCommandHandler;
import revxrsal.commands.bukkit.annotation.CommandPermission;
@@ -24,19 +29,53 @@ import static com.artillexstudios.axtrade.AxTrade.MESSAGEUTILS;
public class Commands implements OrphanCommand {
- @DefaultFor({"~", "~ help"})
public void help(@NotNull CommandSender sender) {
- if (!sender.hasPermission("axtrade.admin")) {
- for (String m : LANG.getStringList("player-help")) {
- sender.sendMessage(StringUtils.formatToString(m));
- }
- } else {
+ if (sender.hasPermission("axtrade.admin")) {
for (String m : LANG.getStringList("admin-help")) {
sender.sendMessage(StringUtils.formatToString(m));
}
+ } else {
+ for (String m : LANG.getStringList("player-help")) {
+ sender.sendMessage(StringUtils.formatToString(m));
+ }
}
}
+ @DefaultFor({"~"})
+ public void trade(@NotNull Player sender, @Optional Player other) {
+ if (other == null) {
+ help(sender);
+ return;
+ }
+
+ Requests.addRequest(sender, other);
+ }
+
+ @Subcommand("accept")
+ public void accept(@NotNull Player sender, @NotNull Player other) {
+ var request = Requests.getRequest(sender, other);
+ if (request == null || request.getSender().equals(sender)) {
+ MESSAGEUTILS.sendLang(sender, "request.no-request", Map.of("%player%", other.getName()));
+ return;
+ }
+
+ Requests.addRequest(sender, other);
+ }
+
+ @Subcommand("deny")
+ public void deny(@NotNull Player sender, @NotNull Player other) {
+ var request = Requests.getRequest(sender, other);
+ if (request == null || request.getSender().equals(sender)) {
+ MESSAGEUTILS.sendLang(sender, "request.no-request", Map.of("%player%", other.getName()));
+ return;
+ }
+
+ MESSAGEUTILS.sendLang(request.getSender(), "request.deny-sender", Map.of("%player%", request.getReceiver().getName()));
+ MESSAGEUTILS.sendLang(request.getReceiver(), "request.deny-receiver", Map.of("%player%", request.getSender().getName()));
+ SoundUtils.playSound(request.getSender(), "deny");
+ SoundUtils.playSound(request.getReceiver(), "deny");
+ }
+
@Subcommand("reload")
@CommandPermission(value = "axtrade.admin", defaultAccess = PermissionDefault.OP)
public void reload(@NotNull CommandSender sender) {
@@ -61,6 +100,9 @@ public class Commands implements OrphanCommand {
Commands.registerCommand();
+ new HookManager().updateHooks();
+ NumberUtils.reload();
+
Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("FFDD╚ AAFFDDSuccessful reload!"));
MESSAGEUTILS.sendLang(sender, "reload.success");
}
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/HookManager.java b/src/main/java/com/artillexstudios/axtrade/hooks/HookManager.java
new file mode 100644
index 0000000..aa19e79
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/HookManager.java
@@ -0,0 +1,124 @@
+package com.artillexstudios.axtrade.hooks;
+
+import com.artillexstudios.axapi.utils.StringUtils;
+import com.artillexstudios.axtrade.hooks.currency.AxQuestBoardHook;
+import com.artillexstudios.axtrade.hooks.currency.CoinsEngineHook;
+import com.artillexstudios.axtrade.hooks.currency.CurrencyHook;
+import com.artillexstudios.axtrade.hooks.currency.ExperienceHook;
+import com.artillexstudios.axtrade.hooks.currency.KingdomsXHook;
+import com.artillexstudios.axtrade.hooks.currency.PlaceholderCurrencyHook;
+import com.artillexstudios.axtrade.hooks.currency.PlayerPointsHook;
+import com.artillexstudios.axtrade.hooks.currency.RivalHarvesterHoesHook;
+import com.artillexstudios.axtrade.hooks.currency.RoyaleEconomyHook;
+import com.artillexstudios.axtrade.hooks.currency.SuperMobCoinsHook;
+import com.artillexstudios.axtrade.hooks.currency.TheOnlyMobCoins;
+import com.artillexstudios.axtrade.hooks.currency.TokenManagerHook;
+import com.artillexstudios.axtrade.hooks.currency.UltraEconomyHook;
+import com.artillexstudios.axtrade.hooks.currency.VaultHook;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+
+import static com.artillexstudios.axtrade.AxTrade.HOOKS;
+
+public class HookManager {
+ private static final ArrayList currency = new ArrayList<>();
+
+ public void setupHooks() {
+ updateHooks();
+ }
+
+ public void updateHooks() {
+ currency.removeIf(currencyHook -> !currencyHook.isPersistent());
+
+ if (HOOKS.getBoolean("currencies.Experience.register", true))
+ currency.add(new ExperienceHook());
+
+ if (HOOKS.getBoolean("currencies.Vault.register", true) && Bukkit.getPluginManager().getPlugin("Vault") != null) {
+ currency.add(new VaultHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into Vault!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.PlayerPoints.register", true) && Bukkit.getPluginManager().getPlugin("PlayerPoints") != null) {
+ currency.add(new PlayerPointsHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into PlayerPoints!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.CoinsEngine.register", true) && Bukkit.getPluginManager().getPlugin("CoinsEngine") != null) {
+ currency.add(new CoinsEngineHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into CoinsEngine!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.RoyaleEconomy.register", true) && Bukkit.getPluginManager().getPlugin("RoyaleEconomy") != null) {
+ currency.add(new RoyaleEconomyHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into RoyaleEconomy!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.UltraEconomy.register", true) && Bukkit.getPluginManager().getPlugin("UltraEconomy") != null) {
+ currency.add(new UltraEconomyHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into UltraEconomy!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.KingdomsX.register", true) && Bukkit.getPluginManager().getPlugin("Kingdoms") != null) {
+ currency.add(new KingdomsXHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into KingdomsX!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.RivalHarvesterHoes.register", true) && Bukkit.getPluginManager().getPlugin("RivalHarvesterHoes") != null) {
+ currency.add(new RivalHarvesterHoesHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into RivalHarvesterHoes!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.SuperMobCoins.register", true) && Bukkit.getPluginManager().getPlugin("SuperMobCoins") != null) {
+ currency.add(new SuperMobCoinsHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into SuperMobCoins!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.TheOnly-MobCoins.register", true) && Bukkit.getPluginManager().getPlugin("TheOnly-MobCoins") != null) {
+ currency.add(new TheOnlyMobCoins());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into TheOnly-MobCoins!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.TokenManager.register", true) && Bukkit.getPluginManager().getPlugin("TokenManager") != null) {
+ currency.add(new TokenManagerHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into TokenManager!"));
+ }
+
+ if (HOOKS.getBoolean("currencies.AxQuestBoard.register", true) && Bukkit.getPluginManager().getPlugin("AxQuestBoard") != null) {
+ currency.add(new AxQuestBoardHook());
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into AxQuestBoard!"));
+ }
+
+ for (String str : HOOKS.getSection("placeholder-currencies").getRoutesAsStrings(false)) {
+ if (!HOOKS.getBoolean("placeholder-currencies." + str + ".register", false)) continue;
+ currency.add(new PlaceholderCurrencyHook(str, HOOKS.getSection("placeholder-currencies." + str)));
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Loaded placeholder currency " + str + "!"));
+ }
+
+ for (CurrencyHook hook : currency) hook.setup();
+ }
+
+ @SuppressWarnings("unused")
+ public static void registerCurrencyHook(@NotNull Plugin plugin, @NotNull CurrencyHook currencyHook) {
+ currency.add(currencyHook);
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("!FF33[AxTrade] Hooked into " + plugin.getName() + "! Note: You must set the currency provider to CUSTOM or it will be overridden after reloading!"));
+ }
+
+ @NotNull
+ public static ArrayList getCurrency() {
+ return currency;
+ }
+
+ @Nullable
+ public static CurrencyHook getCurrencyHook(@NotNull String name) {
+ for (CurrencyHook hook : currency) {
+ if (!hook.getName().equals(name)) continue;
+ return hook;
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/AxQuestBoardHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/AxQuestBoardHook.java
new file mode 100644
index 0000000..a938cb7
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/AxQuestBoardHook.java
@@ -0,0 +1,48 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import com.artillexstudios.axquestboard.api.AxQuestBoardAPI;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class AxQuestBoardHook implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "AxQuestBoard";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return AxQuestBoardAPI.getPoints(player);
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ AxQuestBoardAPI.modifyPoints(player, (int) amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ AxQuestBoardAPI.modifyPoints(player, (int) amount * -1);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/CoinsEngineHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/CoinsEngineHook.java
new file mode 100644
index 0000000..81b636d
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/CoinsEngineHook.java
@@ -0,0 +1,57 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+import su.nightexpress.coinsengine.api.CoinsEngineAPI;
+import su.nightexpress.coinsengine.api.currency.Currency;
+
+import java.util.UUID;
+
+import static com.artillexstudios.axtrade.AxTrade.HOOKS;
+
+public class CoinsEngineHook implements CurrencyHook {
+ private Currency currency = null;
+
+ @Override
+ public void setup() {
+ currency = CoinsEngineAPI.getCurrency(HOOKS.getString("currencies.CoinsEngine.currency-name", "coins"));
+ }
+
+ @Override
+ public String getName() {
+ return "CoinsEngine";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return false;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return true;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ if (currency == null) return 0;
+ return CoinsEngineAPI.getBalance(Bukkit.getPlayer(player), currency);
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ if (currency == null) return;
+ CoinsEngineAPI.addBalance(Bukkit.getPlayer(player), currency, amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ if (currency == null) return;
+ CoinsEngineAPI.removeBalance(Bukkit.getPlayer(player), currency, amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/CurrencyHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/CurrencyHook.java
new file mode 100644
index 0000000..3b7db74
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/CurrencyHook.java
@@ -0,0 +1,23 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public interface CurrencyHook {
+ void setup();
+
+ String getName();
+
+ boolean worksOffline();
+
+ boolean usesDouble();
+
+ boolean isPersistent();
+
+ double getBalance(@NotNull UUID player);
+
+ void giveBalance(@NotNull UUID player, double amount);
+
+ void takeBalance(@NotNull UUID player, double amount);
+}
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/ExperienceHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/ExperienceHook.java
new file mode 100644
index 0000000..afcd2ba
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/ExperienceHook.java
@@ -0,0 +1,120 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class ExperienceHook implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "Experience";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return false;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ final Player pl = Bukkit.getPlayer(player);
+ return getExp(pl);
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ final Player pl = Bukkit.getPlayer(player);
+ changeExp(pl, (int) amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ final Player pl = Bukkit.getPlayer(player);
+ changeExp(pl, (int) (amount * -1));
+ }
+
+ // credit: https://gist.githubusercontent.com/Jikoo/30ec040443a4701b8980/raw/0745ca25a8aaaf749ba2f2164a809e998f6a37c4/Experience.java
+ private int getExp(@NotNull Player player) {
+ return getExpFromLevel(player.getLevel()) + Math.round(getExpToNext(player.getLevel()) * player.getExp());
+ }
+
+ private int getExpFromLevel(int level) {
+ if (level > 30) {
+ return (int) (4.5 * level * level - 162.5 * level + 2220);
+ }
+ if (level > 15) {
+ return (int) (2.5 * level * level - 40.5 * level + 360);
+ }
+ return level * level + 6 * level;
+ }
+
+ private double getLevelFromExp(long exp) {
+ int level = getIntLevelFromExp(exp);
+
+ // Get remaining exp progressing towards next level. Cast to float for next bit of math.
+ float remainder = exp - (float) getExpFromLevel(level);
+
+ // Get level progress with float precision.
+ float progress = remainder / getExpToNext(level);
+
+ // Slap both numbers together and call it a day. While it shouldn't be possible for progress
+ // to be an invalid value (value < 0 || 1 <= value)
+ return ((double) level) + progress;
+ }
+
+ private int getIntLevelFromExp(long exp) {
+ if (exp > 1395) {
+ return (int) ((Math.sqrt(72 * exp - 54215D) + 325) / 18);
+ }
+ if (exp > 315) {
+ return (int) (Math.sqrt(40 * exp - 7839D) / 10 + 8.1);
+ }
+ if (exp > 0) {
+ return (int) (Math.sqrt(exp + 9D) - 3);
+ }
+ return 0;
+ }
+
+ private int getExpToNext(int level) {
+ if (level >= 30) {
+ // Simplified formula. Internal: 112 + (level - 30) * 9
+ return level * 9 - 158;
+ }
+ if (level >= 15) {
+ // Simplified formula. Internal: 37 + (level - 15) * 5
+ return level * 5 - 38;
+ }
+ // Internal: 7 + level * 2
+ return level * 2 + 7;
+ }
+
+ private void changeExp(Player player, int exp) {
+ exp += getExp(player);
+
+ if (exp < 0) {
+ exp = 0;
+ }
+
+ double levelAndExp = getLevelFromExp(exp);
+ int level = (int) levelAndExp;
+ player.setLevel(level);
+ player.setExp((float) (levelAndExp - level));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/KingdomsXHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/KingdomsXHook.java
new file mode 100644
index 0000000..628bcb4
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/KingdomsXHook.java
@@ -0,0 +1,52 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import org.jetbrains.annotations.NotNull;
+import org.kingdoms.constants.player.KingdomPlayer;
+
+import java.util.UUID;
+
+public class KingdomsXHook implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "KingdomsX";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ final KingdomPlayer kingdomPlayer = KingdomPlayer.getKingdomPlayer(player);
+ if (kingdomPlayer.getKingdom() == null) return 0.0D;
+ return kingdomPlayer.getKingdom().getResourcePoints();
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ final KingdomPlayer kingdomPlayer = KingdomPlayer.getKingdomPlayer(player);
+ kingdomPlayer.getKingdom().addResourcePoints((long) amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ final KingdomPlayer kingdomPlayer = KingdomPlayer.getKingdomPlayer(player);
+ kingdomPlayer.getKingdom().addResourcePoints((long) (amount * -1));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/PlaceholderCurrencyHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/PlaceholderCurrencyHook.java
new file mode 100644
index 0000000..71adbc1
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/PlaceholderCurrencyHook.java
@@ -0,0 +1,70 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import com.artillexstudios.axapi.libs.boostedyaml.boostedyaml.block.implementation.Section;
+import me.clip.placeholderapi.PlaceholderAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class PlaceholderCurrencyHook implements CurrencyHook {
+ private final String name;
+ private final Section section;
+
+ public PlaceholderCurrencyHook(String name, Section section) {
+ this.name = name;
+ this.section = section;
+ }
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return section.getBoolean("works-offline", false);
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return section.getBoolean("uses-double", false);
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ final OfflinePlayer pl = Bukkit.getOfflinePlayer(player);
+ final String placeholder = section.getString("settings.raw-placeholder");
+ return Double.parseDouble(PlaceholderAPI.setPlaceholders(pl.getPlayer() == null ? pl : pl.getPlayer(), placeholder));
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ final OfflinePlayer pl = Bukkit.getOfflinePlayer(player);
+ if (pl.getName() == null) return;
+ final String placeholder = section.getString("settings.give-command")
+ .replace("%amount%", "" + amount)
+ .replace("%player%", pl.getName());
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), placeholder);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ final OfflinePlayer pl = Bukkit.getOfflinePlayer(player);
+ if (pl.getName() == null) return;
+ final String placeholder = section.getString("settings.take-command")
+ .replace("%amount%", "" + amount)
+ .replace("%player%", pl.getName());
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), placeholder);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/PlayerPointsHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/PlayerPointsHook.java
new file mode 100644
index 0000000..ff60dd3
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/PlayerPointsHook.java
@@ -0,0 +1,51 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import org.black_ixx.playerpoints.PlayerPoints;
+import org.black_ixx.playerpoints.PlayerPointsAPI;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class PlayerPointsHook implements CurrencyHook {
+ private PlayerPointsAPI econ = null;
+
+ @Override
+ public void setup() {
+ econ = PlayerPoints.getInstance().getAPI();
+ }
+
+ @Override
+ public String getName() {
+ return "PlayerPoints";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return econ.look(player);
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ econ.give(player, (int) amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ econ.take(player, (int) Math.round(amount));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/RivalHarvesterHoesHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/RivalHarvesterHoesHook.java
new file mode 100644
index 0000000..76f42e3
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/RivalHarvesterHoesHook.java
@@ -0,0 +1,49 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import me.rivaldev.harvesterhoes.Main;
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class RivalHarvesterHoesHook implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "RivalHarvesterHoes";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return true;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return Main.instance.getEconomy().getEconomyAmount(Bukkit.getOfflinePlayer(player));
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ Main.instance.getEconomy().giveEconomyAmount(Bukkit.getOfflinePlayer(player), amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ Main.instance.getEconomy().removeEconomyAmount(Bukkit.getOfflinePlayer(player), amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/RoyaleEconomyHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/RoyaleEconomyHook.java
new file mode 100644
index 0000000..84d20f7
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/RoyaleEconomyHook.java
@@ -0,0 +1,48 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import me.qKing12.RoyaleEconomy.RoyaleEconomy;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class RoyaleEconomyHook implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "RoyaleEconomy";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return true;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return RoyaleEconomy.apiHandler.balance.getBalance(player.toString());
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ RoyaleEconomy.apiHandler.balance.addBalance(player.toString(), amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ RoyaleEconomy.apiHandler.balance.removeBalance(player.toString(), amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/SuperMobCoinsHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/SuperMobCoinsHook.java
new file mode 100644
index 0000000..3b3d3ce
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/SuperMobCoinsHook.java
@@ -0,0 +1,51 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import me.swanis.mobcoins.MobCoinsAPI;
+import me.swanis.mobcoins.profile.Profile;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class SuperMobCoinsHook implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "SuperMobCoins";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return MobCoinsAPI.getProfileManager().getProfile(player).getMobCoins();
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ final Profile profile = MobCoinsAPI.getProfileManager().getProfile(player);
+ profile.setMobCoins((long) (profile.getMobCoins() + amount));
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ final Profile profile = MobCoinsAPI.getProfileManager().getProfile(player);
+ profile.setMobCoins((long) (profile.getMobCoins() - amount));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/TheOnlyMobCoins.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/TheOnlyMobCoins.java
new file mode 100644
index 0000000..644b3df
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/TheOnlyMobCoins.java
@@ -0,0 +1,52 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import me.aglerr.mobcoins.api.MobCoinsAPI;
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class TheOnlyMobCoins implements CurrencyHook {
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public String getName() {
+ return "TheOnly-MobCoins";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return false;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return true;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ if (MobCoinsAPI.getPlayerData(Bukkit.getPlayer(player)) == null) return 0;
+ return MobCoinsAPI.getPlayerData(Bukkit.getPlayer(player)).getCoins();
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ if (MobCoinsAPI.getPlayerData(Bukkit.getPlayer(player)) == null) return;
+ MobCoinsAPI.getPlayerData(Bukkit.getPlayer(player)).addCoins(amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ if (MobCoinsAPI.getPlayerData(Bukkit.getPlayer(player)) == null) return;
+ MobCoinsAPI.getPlayerData(Bukkit.getPlayer(player)).reduceCoins(amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/TokenManagerHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/TokenManagerHook.java
new file mode 100644
index 0000000..b4331ef
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/TokenManagerHook.java
@@ -0,0 +1,51 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import me.realized.tokenmanager.api.TokenManager;
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class TokenManagerHook implements CurrencyHook {
+ private TokenManager eco;
+
+ @Override
+ public void setup() {
+ eco = (TokenManager) Bukkit.getPluginManager().getPlugin("TokenManager");
+ }
+
+ @Override
+ public String getName() {
+ return "TokenManager";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return false;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return eco.getTokens(Bukkit.getPlayer(player)).orElse(0);
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ eco.addTokens(Bukkit.getPlayer(player), (long) amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ eco.removeTokens(Bukkit.getPlayer(player), (long) amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/UltraEconomyHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/UltraEconomyHook.java
new file mode 100644
index 0000000..95dcec0
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/UltraEconomyHook.java
@@ -0,0 +1,63 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import me.TechsCode.UltraEconomy.UltraEconomy;
+import me.TechsCode.UltraEconomy.objects.Account;
+import me.TechsCode.UltraEconomy.objects.Currency;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Optional;
+import java.util.UUID;
+
+import static com.artillexstudios.axtrade.AxTrade.HOOKS;
+
+public class UltraEconomyHook implements CurrencyHook {
+ private Currency currency = null;
+
+ @Override
+ public void setup() {
+ final Optional currencyOptional = UltraEconomy.getAPI().getCurrencies().name(HOOKS.getString("currencies.UltraEconomy.currency-name", "coins"));
+ if (!currencyOptional.isPresent()) throw new RuntimeException("Currency not found!");
+ currency = currencyOptional.get();
+ }
+
+ @Override
+ public String getName() {
+ return "UltraEconomy";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return true;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ final Optional account = UltraEconomy.getAPI().getAccounts().uuid(player);
+ if (!account.isPresent()) return 0.0D;
+ return account.get().getBalance(currency).getOnHand();
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ final Optional account = UltraEconomy.getAPI().getAccounts().uuid(player);
+ if (account.isEmpty()) return;
+ account.get().addBalance(currency, amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ final Optional account = UltraEconomy.getAPI().getAccounts().uuid(player);
+ if (account.isEmpty()) return;
+ account.get().removeBalance(currency, amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/hooks/currency/VaultHook.java b/src/main/java/com/artillexstudios/axtrade/hooks/currency/VaultHook.java
new file mode 100644
index 0000000..9c27d84
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/hooks/currency/VaultHook.java
@@ -0,0 +1,55 @@
+package com.artillexstudios.axtrade.hooks.currency;
+
+import net.milkbowl.vault.economy.Economy;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.RegisteredServiceProvider;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.UUID;
+
+public class VaultHook implements CurrencyHook {
+ private Economy econ = null;
+
+ @Override
+ public void setup() {
+ final RegisteredServiceProvider rsp = Bukkit.getServer().getServicesManager().getRegistration(Economy.class);
+ if (rsp == null) return;
+
+ econ = rsp.getProvider();
+ }
+
+ @Override
+ public String getName() {
+ return "Vault";
+ }
+
+ @Override
+ public boolean worksOffline() {
+ return true;
+ }
+
+ @Override
+ public boolean usesDouble() {
+ return true;
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return false;
+ }
+
+ @Override
+ public double getBalance(@NotNull UUID player) {
+ return econ.getBalance(Bukkit.getOfflinePlayer(player));
+ }
+
+ @Override
+ public void giveBalance(@NotNull UUID player, double amount) {
+ econ.depositPlayer(Bukkit.getOfflinePlayer(player), amount);
+ }
+
+ @Override
+ public void takeBalance(@NotNull UUID player, double amount) {
+ econ.withdrawPlayer(Bukkit.getOfflinePlayer(player), amount);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/listeners/PlayerInteractEntityListener.java b/src/main/java/com/artillexstudios/axtrade/listeners/PlayerInteractEntityListener.java
new file mode 100644
index 0000000..4e2d67c
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/listeners/PlayerInteractEntityListener.java
@@ -0,0 +1,30 @@
+package com.artillexstudios.axtrade.listeners;
+
+import com.artillexstudios.axtrade.commands.Commands;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.WeakHashMap;
+
+public class PlayerInteractEntityListener implements Listener {
+ private final WeakHashMap cd = new WeakHashMap<>();
+
+ @EventHandler (ignoreCancelled = true)
+ public void onClick(@NotNull PlayerInteractEntityEvent event) {
+ final Player player = event.getPlayer();
+
+ if (cd.containsKey(player) && System.currentTimeMillis() - cd.get(player) < 100L) return;
+
+ if (!player.isSneaking()) return;
+ if (!(event.getRightClicked() instanceof Player)) return;
+
+ cd.put(player, System.currentTimeMillis());
+ final Player sendTo = (Player) event.getRightClicked();
+ if (!sendTo.isOnline()) return;
+
+ new Commands().trade(player, sendTo);
+ }
+}
diff --git a/src/main/java/com/artillexstudios/axtrade/listeners/TradeListeners.java b/src/main/java/com/artillexstudios/axtrade/listeners/TradeListeners.java
new file mode 100644
index 0000000..1ccb230
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/listeners/TradeListeners.java
@@ -0,0 +1,59 @@
+package com.artillexstudios.axtrade.listeners;
+
+import com.artillexstudios.axtrade.trade.Trade;
+import com.artillexstudios.axtrade.trade.Trades;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.jetbrains.annotations.NotNull;
+
+public class TradeListeners implements Listener {
+
+ @EventHandler
+ public void onQuit(@NotNull PlayerQuitEvent event) {
+ final Player player = event.getPlayer();
+ final Trade trade = Trades.getTrade(player);
+ if (trade == null) return;
+ trade.abort();
+ }
+
+ @EventHandler
+ public void onDrop(@NotNull PlayerDropItemEvent event) {
+ final Player player = event.getPlayer();
+ final Trade trade = Trades.getTrade(player);
+ if (trade == null) return;
+ event.setCancelled(true);
+ }
+
+ @EventHandler
+ public void onMove(@NotNull PlayerMoveEvent event) {
+ final Player player = event.getPlayer();
+ final Trade trade = Trades.getTrade(player);
+ if (trade == null) return;
+ if (System.currentTimeMillis() - trade.getPrepTime() < 1_000L) return;
+ trade.abort();
+ }
+
+ @EventHandler
+ public void onInteract(@NotNull PlayerInteractEvent event) {
+ final Player player = event.getPlayer();
+ final Trade trade = Trades.getTrade(player);
+ if (trade == null) return;
+ event.setCancelled(true);
+ trade.abort();
+ }
+
+ @EventHandler
+ public void onCommand(@NotNull PlayerCommandPreprocessEvent event) {
+ final Player player = event.getPlayer();
+ final Trade trade = Trades.getTrade(player);
+ if (trade == null) return;
+ event.setCancelled(true);
+ trade.abort();
+ }
+}
diff --git a/src/main/java/com/artillexstudios/axtrade/request/Request.java b/src/main/java/com/artillexstudios/axtrade/request/Request.java
new file mode 100644
index 0000000..b243aa4
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/request/Request.java
@@ -0,0 +1,27 @@
+package com.artillexstudios.axtrade.request;
+
+import org.bukkit.entity.Player;
+
+public class Request {
+ private final long time;
+ private final Player sender;
+ private final Player receiver;
+
+ public Request(Player sender, Player receiver) {
+ this.time = System.currentTimeMillis();
+ this.sender = sender;
+ this.receiver = receiver;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public Player getReceiver() {
+ return receiver;
+ }
+
+ public Player getSender() {
+ return sender;
+ }
+}
diff --git a/src/main/java/com/artillexstudios/axtrade/request/Requests.java b/src/main/java/com/artillexstudios/axtrade/request/Requests.java
new file mode 100644
index 0000000..6e9f239
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/request/Requests.java
@@ -0,0 +1,73 @@
+package com.artillexstudios.axtrade.request;
+
+import com.artillexstudios.axtrade.trade.Trades;
+import com.artillexstudios.axtrade.utils.SoundUtils;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import static com.artillexstudios.axtrade.AxTrade.CONFIG;
+import static com.artillexstudios.axtrade.AxTrade.MESSAGEUTILS;
+
+public class Requests {
+ private static final ArrayList requests = new ArrayList<>();
+
+ public static void addRequest(@NotNull Player sender, @NotNull Player receiver) {
+ if (sender.equals(receiver)) {
+ MESSAGEUTILS.sendLang(sender, "request.cant-trade-self", Map.of("%player%", receiver.getName()));
+ return;
+ }
+
+ if (Trades.isTrading(receiver) || Trades.isTrading(sender)) {
+ MESSAGEUTILS.sendLang(sender, "request.already-in-trade", Map.of("%player%", receiver.getName()));
+ return;
+ }
+
+ int maxDist = CONFIG.getInt("trade-max-distance", 10);
+ if (maxDist != -1 && (sender.getWorld() != receiver.getWorld() || maxDist < sender.getLocation().distance(receiver.getLocation()))) {
+ MESSAGEUTILS.sendLang(sender, "request.too-far", Map.of("%player%", receiver.getName()));
+ return;
+ }
+
+ var request = Requests.getRequest(sender, receiver);
+ if (request != null && !request.getSender().equals(sender)) {
+ Trades.addTrade(sender, receiver);
+ requests.remove(request);
+ return;
+ }
+
+ if (request != null && System.currentTimeMillis() - request.getTime() < CONFIG.getInt("trade-request-expire-seconds", 60) * 1_000L) {
+ MESSAGEUTILS.sendLang(sender, "request.already-sent", Map.of("%player%", receiver.getName()));
+ return;
+ }
+
+ requests.add(new Request(sender, receiver));
+
+ MESSAGEUTILS.sendLang(sender, "request.sent-sender", Map.of("%player%", receiver.getName()));
+ MESSAGEUTILS.sendLang(receiver, "request.sent-receiver", Map.of("%player%", sender.getName()));
+ SoundUtils.playSound(sender, "requested");
+ SoundUtils.playSound(receiver, "requested");
+ }
+
+ public static boolean hasRequest(Player p1, Player p2) {
+ for (Request rq : requests) {
+ if (!((rq.getSender() == p1 || rq.getSender() == p2) && (rq.getReceiver() == p1 || rq.getReceiver() == p2))) continue;
+ return true;
+ }
+
+ return false;
+ }
+
+ @Nullable
+ public static Request getRequest(Player p1, Player p2) {
+ for (Request rq : requests) {
+ if (!((rq.getSender() == p1 || rq.getSender() == p2) && (rq.getReceiver() == p1 || rq.getReceiver() == p2))) continue;
+ return rq;
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/artillexstudios/axtrade/trade/GuiFrame.java b/src/main/java/com/artillexstudios/axtrade/trade/GuiFrame.java
index 3812445..c6f5fbd 100644
--- a/src/main/java/com/artillexstudios/axtrade/trade/GuiFrame.java
+++ b/src/main/java/com/artillexstudios/axtrade/trade/GuiFrame.java
@@ -22,6 +22,7 @@ public class GuiFrame {
protected final Config file;
protected BaseGui gui;
protected Player player;
+ protected boolean opened = false;
public GuiFrame(Config file, Player player) {
this.file = file;
@@ -69,7 +70,13 @@ public class GuiFrame {
final ItemStack it = buildItem(itemRoute, replacements);
it.setAmount(amount);
final GuiItem guiItem = new GuiItem(it, action);
- gui.setItem(getSlots(slotRoute), guiItem);
+ if (opened) {
+ for (int slot : getSlots(slotRoute)) {
+ gui.updateItem(slot, guiItem);
+ }
+ }
+ else
+ gui.setItem(getSlots(slotRoute), guiItem);
}
protected List getSlots(String r) {
diff --git a/src/main/java/com/artillexstudios/axtrade/trade/Trade.java b/src/main/java/com/artillexstudios/axtrade/trade/Trade.java
index cdd4d4e..2fbdeef 100644
--- a/src/main/java/com/artillexstudios/axtrade/trade/Trade.java
+++ b/src/main/java/com/artillexstudios/axtrade/trade/Trade.java
@@ -1,6 +1,8 @@
package com.artillexstudios.axtrade.trade;
import com.artillexstudios.axapi.scheduler.Scheduler;
+import com.artillexstudios.axtrade.hooks.currency.CurrencyHook;
+import com.artillexstudios.axtrade.utils.SoundUtils;
import org.bukkit.entity.Player;
import java.util.Map;
@@ -10,7 +12,8 @@ import static com.artillexstudios.axtrade.AxTrade.MESSAGEUTILS;
public class Trade {
protected final TradePlayer player1;
protected final TradePlayer player2;
- private boolean ended = false;
+ protected boolean ended = false;
+ protected long prepTime = System.currentTimeMillis();
public Trade(Player p1, Player p2) {
this.player1 = new TradePlayer(this, p1);
@@ -26,9 +29,18 @@ public class Trade {
public void abort() {
if (ended) return;
- // todo: refund items
- MESSAGEUTILS.sendLang(player1.getPlayer(), "trade-aborted", Map.of("%player%", player2.getPlayer().getName()));
- MESSAGEUTILS.sendLang(player2.getPlayer(), "trade-aborted", Map.of("%player%", player1.getPlayer().getName()));
+ player1.getTradeGui().getItems().forEach(itemStack -> {
+ if (itemStack == null) return;
+ player1.getPlayer().getInventory().addItem(itemStack);
+ });
+ player2.getTradeGui().getItems().forEach(itemStack -> {
+ if (itemStack == null) return;
+ player2.getPlayer().getInventory().addItem(itemStack);
+ });
+ MESSAGEUTILS.sendLang(player1.getPlayer(), "trade.aborted", Map.of("%player%", player2.getPlayer().getName()));
+ MESSAGEUTILS.sendLang(player2.getPlayer(), "trade.aborted", Map.of("%player%", player1.getPlayer().getName()));
+ SoundUtils.playSound(player1.getPlayer(), "aborted");
+ SoundUtils.playSound(player2.getPlayer(), "aborted");
end();
}
@@ -41,4 +53,50 @@ public class Trade {
player2.getPlayer().closeInventory();
player2.getPlayer().updateInventory();
}
+
+ public void complete() {
+ for (Map.Entry entry : player1.getCurrencies().entrySet()) {
+ if (entry.getKey().getBalance(player1.getPlayer().getUniqueId()) < entry.getValue()) {
+ abort();
+ return;
+ }
+ }
+
+ for (Map.Entry entry : player2.getCurrencies().entrySet()) {
+ if (entry.getKey().getBalance(player2.getPlayer().getUniqueId()) < entry.getValue()) {
+ abort();
+ return;
+ }
+ }
+
+ for (Map.Entry entry : player1.getCurrencies().entrySet()) {
+ entry.getKey().takeBalance(player1.getPlayer().getUniqueId(), entry.getValue());
+ entry.getKey().giveBalance(player2.getPlayer().getUniqueId(), entry.getValue());
+ }
+
+ for (Map.Entry entry : player2.getCurrencies().entrySet()) {
+ entry.getKey().takeBalance(player2.getPlayer().getUniqueId(), entry.getValue());
+ entry.getKey().giveBalance(player1.getPlayer().getUniqueId(), entry.getValue());
+ }
+
+ MESSAGEUTILS.sendLang(player1.getPlayer(), "trade.completed", Map.of("%player%", player2.getPlayer().getName()));
+ MESSAGEUTILS.sendLang(player2.getPlayer(), "trade.completed", Map.of("%player%", player1.getPlayer().getName()));
+ SoundUtils.playSound(player1.getPlayer(), "completed");
+ SoundUtils.playSound(player2.getPlayer(), "completed");
+
+ player1.getTradeGui().getItems().forEach(itemStack -> {
+ if (itemStack == null) return;
+ player2.getPlayer().getInventory().addItem(itemStack);
+ });
+ player2.getTradeGui().getItems().forEach(itemStack -> {
+ if (itemStack == null) return;
+ player1.getPlayer().getInventory().addItem(itemStack);
+ });
+
+ end();
+ }
+
+ public long getPrepTime() {
+ return prepTime;
+ }
}
diff --git a/src/main/java/com/artillexstudios/axtrade/trade/TradeGui.java b/src/main/java/com/artillexstudios/axtrade/trade/TradeGui.java
index 4b423b0..33cf339 100644
--- a/src/main/java/com/artillexstudios/axtrade/trade/TradeGui.java
+++ b/src/main/java/com/artillexstudios/axtrade/trade/TradeGui.java
@@ -1,37 +1,47 @@
package com.artillexstudios.axtrade.trade;
-import com.artillexstudios.axapi.scheduler.ScheduledTask;
import com.artillexstudios.axapi.scheduler.Scheduler;
import com.artillexstudios.axapi.utils.StringUtils;
+import com.artillexstudios.axtrade.AxTrade;
+import com.artillexstudios.axtrade.utils.NumberUtils;
+import de.rapha149.signgui.SignGUI;
+import de.rapha149.signgui.SignGUIAction;
import dev.triumphteam.gui.guis.Gui;
+import dev.triumphteam.gui.guis.GuiItem;
import dev.triumphteam.gui.guis.StorageGui;
+import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.function.Consumer;
import static com.artillexstudios.axtrade.AxTrade.GUIS;
+import static com.artillexstudios.axtrade.AxTrade.LANG;
+import static com.artillexstudios.axtrade.AxTrade.MESSAGEUTILS;
public class TradeGui extends GuiFrame {
private final Trade trade;
private final TradePlayer player;
- private final boolean shouldMirror;
protected final StorageGui gui;
protected final List slots = getSlots("own-slots");
+ protected final List otherSlots = getSlots("partner-slots");
+ private boolean inSign = false;
public TradeGui(@NotNull Trade trade, @NotNull TradePlayer player) {
super(GUIS, player.getPlayer());
this.trade = trade;
this.player = player;
- this.shouldMirror = player == trade.player2;
this.gui = Gui.storage()
.rows(GUIS.getInt("rows",6))
.title(StringUtils.format(GUIS.getString("title").replace("%player%", player.getOtherPlayer().getPlayer().getName())))
+ .disableItemDrop()
.create();
setGui(gui);
gui.setDefaultTopClickAction(event -> {
+ player.cancel();
if (!slots.contains(event.getSlot())) {
event.setCancelled(true);
if (event.getCursor() == null) return;
@@ -42,8 +52,33 @@ public class TradeGui extends GuiFrame {
Scheduler.get().run(scheduledTask -> trade.update());
});
+ gui.setDragAction(event -> {
+ if (event.getInventory() == player.getPlayer().getInventory()) return;
+ if (!new HashSet<>(slots).containsAll(event.getInventorySlots())) {
+ event.setCancelled(true);
+ return;
+ }
+ player.cancel();
+ Scheduler.get().run(scheduledTask -> trade.update());
+ });
+
+ gui.setPlayerInventoryAction(event -> {
+ if (event.isShiftClick() && !slots.contains(event.getView().getTopInventory().firstEmpty())) {
+ event.setCancelled(true);
+ return;
+ }
+ player.cancel();
+ Scheduler.get().run(scheduledTask -> trade.update());
+ });
+
+ gui.setCloseGuiAction(event -> {
+ if (inSign) return;
+ trade.abort();
+ });
+
update();
gui.open(player.getPlayer());
+ opened = true;
}
public void update() {
@@ -51,6 +86,7 @@ public class TradeGui extends GuiFrame {
super.createItem("own.confirm-item.slot", "own.confirm-item.cancel", event -> {
event.setCancelled(true);
player.cancel();
+ trade.update();
}, Map.of(), player.getConfirmed());
} else {
super.createItem("own.confirm-item.slot", "own.confirm-item.accept", event -> {
@@ -68,6 +104,77 @@ public class TradeGui extends GuiFrame {
event.setCancelled(true);
}, Map.of());
}
- gui.update();
+
+ for (String currencyItem : GUIS.getSection("own").getRoutesAsStrings(false)) {
+ final String currencyStr = GUIS.getString("own." + currencyItem + ".currency", null);
+ if (currencyStr == null) continue;
+
+ super.createItem("own." + currencyItem, event -> {
+ event.setCancelled(true);
+ player.cancel();
+ trade.update();
+ inSign = true;
+ trade.prepTime = System.currentTimeMillis();
+ event.getWhoClicked().closeInventory();
+
+ var lines = LANG.getStringList("currency-editor-sign");
+ lines = StringUtils.formatListToString(lines);
+ final SignGUI signGUI = SignGUI.builder().setLines(lines.toArray(new String[0])).setHandler((player1, result) -> List.of(SignGUIAction.runSync(AxTrade.getInstance(), () -> {
+ if (trade.ended) return;
+ trade.prepTime = System.currentTimeMillis();
+ String am = result.getLine(0);
+ TradePlayer.Result addResult = TradePlayer.Result.NOT_A_NUMBER;
+ if (com.artillexstudios.axapi.utils.NumberUtils.isDouble(am) && (addResult = player.setCurrency(currencyStr, Double.parseDouble(am))) == TradePlayer.Result.SUCCESS) {
+ MESSAGEUTILS.sendLang(player1, "currency-editor.success");
+ } else {
+ switch (addResult) {
+ case NOT_ENOUGH_CURRENCY:
+ MESSAGEUTILS.sendLang(player1, "currency-editor.not-enough");
+ break;
+ default:
+ MESSAGEUTILS.sendLang(player1, "currency-editor.failed");
+ break;
+ }
+ }
+ gui.open(player.getPlayer());
+ inSign = false;
+ trade.update();
+ }))).build();
+ signGUI.open(player.getPlayer());
+ }, Map.of("%amount%", NumberUtils.formatNumber(player.getCurrency(currencyStr))));
+ }
+
+ for (String currencyItem : GUIS.getSection("partner").getRoutesAsStrings(false)) {
+ final String currencyStr = GUIS.getString("partner." + currencyItem + ".currency", null);
+ if (currencyStr == null) continue;
+
+ super.createItem("partner." + currencyItem, event -> {
+ event.setCancelled(true);
+ }, Map.of(
+ "%amount%", NumberUtils.formatNumber(player.getOtherPlayer().getCurrency(currencyStr)),
+ "%player%", player.getOtherPlayer().getPlayer().getName()
+ ));
+ }
+
+ for (int slot : otherSlots) {
+ gui.removeItem(slot);
+ }
+
+ if (!opened) return;
+ var otherItems = player.getOtherPlayer().getTradeGui().getItems();
+ int n = 0;
+ for (int slot : otherSlots) {
+ if (otherItems.get(n) != null)
+ gui.updateItem(slot, new GuiItem(otherItems.get(n), event -> event.setCancelled(true)));
+ n++;
+ }
+ }
+
+ public List getItems() {
+ final List items = new ArrayList<>();
+ for (int slot : slots) {
+ items.add(gui.getInventory().getItem(slot));
+ }
+ return items;
}
}
diff --git a/src/main/java/com/artillexstudios/axtrade/trade/TradePlayer.java b/src/main/java/com/artillexstudios/axtrade/trade/TradePlayer.java
index 906286e..17bea1e 100644
--- a/src/main/java/com/artillexstudios/axtrade/trade/TradePlayer.java
+++ b/src/main/java/com/artillexstudios/axtrade/trade/TradePlayer.java
@@ -1,7 +1,12 @@
package com.artillexstudios.axtrade.trade;
+import com.artillexstudios.axtrade.hooks.HookManager;
+import com.artillexstudios.axtrade.hooks.currency.CurrencyHook;
+import com.artillexstudios.axtrade.utils.SoundUtils;
import org.bukkit.entity.Player;
+import java.util.HashMap;
+
import static com.artillexstudios.axtrade.AxTrade.CONFIG;
public class TradePlayer {
@@ -9,6 +14,7 @@ public class TradePlayer {
private TradePlayer otherPlayer;
private TradeGui tradeGui;
private final Trade trade;
+ private final HashMap currencies = new HashMap<>();
// confirmed
// null > not confirmed
@@ -48,12 +54,16 @@ public class TradePlayer {
public void confirm() {
this.confirmed = CONFIG.getInt("trade-confirm-seconds", 10);
trade.update();
+ SoundUtils.playSound(player, "accept");
+ SoundUtils.playSound(otherPlayer.getPlayer(), "accept");
}
public void cancel() {
+ if (confirmed == null) return;
this.confirmed = null;
otherPlayer.setConfirmed(null);
- trade.update();
+ SoundUtils.playSound(player, "cancel");
+ SoundUtils.playSound(otherPlayer.getPlayer(), "cancel");
}
public void setConfirmed(Integer confirmed) {
@@ -63,5 +73,36 @@ public class TradePlayer {
public void tick() {
confirmed -= 1;
trade.update();
+ SoundUtils.playSound(player, "countdown");
+ }
+
+ public HashMap getCurrencies() {
+ return currencies;
+ }
+
+ public double getCurrency(String currency) {
+ final CurrencyHook currencyHook = HookManager.getCurrencyHook(currency);
+ if (currencyHook == null) return 0;
+ if (!currencies.containsKey(currencyHook)) return 0;
+ return currencies.get(currencyHook);
+ }
+
+ public Result setCurrency(String currency, double amount) {
+ if (Double.isNaN(amount)) return Result.NOT_A_NUMBER;
+ final CurrencyHook currencyHook = HookManager.getCurrencyHook(currency);
+ if (currencyHook == null) return Result.CURRENCY_NOT_FOUND;
+ amount = currencyHook.usesDouble() ? amount : Math.round(amount);
+ if (amount < 0.1) return Result.TOO_LOW_VALUE;
+ if (currencyHook.getBalance(player.getUniqueId()) < amount) return Result.NOT_ENOUGH_CURRENCY;
+ currencies.put(currencyHook, amount);
+ return Result.SUCCESS;
+ }
+
+ public enum Result {
+ NOT_A_NUMBER,
+ CURRENCY_NOT_FOUND,
+ TOO_LOW_VALUE,
+ NOT_ENOUGH_CURRENCY,
+ SUCCESS
}
}
diff --git a/src/main/java/com/artillexstudios/axtrade/trade/TradeTicker.java b/src/main/java/com/artillexstudios/axtrade/trade/TradeTicker.java
index 141309f..ea1d3f7 100644
--- a/src/main/java/com/artillexstudios/axtrade/trade/TradeTicker.java
+++ b/src/main/java/com/artillexstudios/axtrade/trade/TradeTicker.java
@@ -2,10 +2,6 @@ package com.artillexstudios.axtrade.trade;
import com.artillexstudios.axapi.scheduler.Scheduler;
-import java.util.Map;
-
-import static com.artillexstudios.axtrade.AxTrade.MESSAGEUTILS;
-
public class TradeTicker {
public void start() {
@@ -14,10 +10,7 @@ public class TradeTicker {
if (!(trade.player1.hasConfirmed() && trade.player2.hasConfirmed())) continue;
if (trade.player1.getConfirmed() == 1) {
- MESSAGEUTILS.sendLang(trade.player1.getPlayer(), "trade-completed", Map.of("%player%", trade.player2.getPlayer().getName()));
- MESSAGEUTILS.sendLang(trade.player2.getPlayer(), "trade-completed", Map.of("%player%", trade.player1.getPlayer().getName()));
- // todo: transfer items
- trade.end();
+ trade.complete();
continue;
}
diff --git a/src/main/java/com/artillexstudios/axtrade/trade/Trades.java b/src/main/java/com/artillexstudios/axtrade/trade/Trades.java
index 7a00a18..325e6e2 100644
--- a/src/main/java/com/artillexstudios/axtrade/trade/Trades.java
+++ b/src/main/java/com/artillexstudios/axtrade/trade/Trades.java
@@ -1,6 +1,8 @@
package com.artillexstudios.axtrade.trade;
+import com.artillexstudios.axtrade.utils.SoundUtils;
import org.bukkit.entity.Player;
+import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Map;
@@ -13,8 +15,10 @@ public class Trades {
public static void addTrade(Player p1, Player p2) {
Trade trade = new Trade(p1, p2);
trades.add(trade);
- MESSAGEUTILS.sendLang(p1, "trade-started", Map.of("%player%", p2.getName()));
- MESSAGEUTILS.sendLang(p2, "trade-started", Map.of("%player%", p1.getName()));
+ MESSAGEUTILS.sendLang(p1, "trade.started", Map.of("%player%", p2.getName()));
+ MESSAGEUTILS.sendLang(p2, "trade.started", Map.of("%player%", p1.getName()));
+ SoundUtils.playSound(p1, "started");
+ SoundUtils.playSound(p2, "started");
}
public static void removeTrade(Trade trade) {
@@ -24,4 +28,13 @@ public class Trades {
public static ArrayList getTrades() {
return trades;
}
+
+ public static boolean isTrading(Player player) {
+ return trades.stream().anyMatch(trade -> trade.player1.getPlayer().equals(player) || trade.player2.getPlayer().equals(player));
+ }
+
+ @Nullable
+ public static Trade getTrade(Player player) {
+ return trades.stream().filter(trade -> trade.player1.getPlayer().equals(player) || trade.player2.getPlayer().equals(player)).findAny().orElse(null);
+ }
}
diff --git a/src/main/java/com/artillexstudios/axtrade/utils/NumberUtils.java b/src/main/java/com/artillexstudios/axtrade/utils/NumberUtils.java
new file mode 100644
index 0000000..fa50a63
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/utils/NumberUtils.java
@@ -0,0 +1,31 @@
+package com.artillexstudios.axtrade.utils;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import static com.artillexstudios.axtrade.AxTrade.CONFIG;
+
+public class NumberUtils {
+ private static NumberFormat formatter = new DecimalFormat(CONFIG.getString("number-formatting.formatted", "#,###.##"));
+
+ public static void reload() {
+ int mode = CONFIG.getInt("number-formatting.mode", 0);
+ switch (mode) {
+ case 0:
+ formatter = new DecimalFormat(CONFIG.getString("number-formatting.formatted", "#,###.##"));
+ break;
+ case 1:
+ final String[] lang = CONFIG.getString("number-formatting.short", "en_US").split("_");
+ formatter = DecimalFormat.getCompactNumberInstance(new Locale(lang[0], lang[1]), NumberFormat.Style.SHORT);
+ break;
+ case 2:
+ formatter = null;
+ break;
+ }
+ }
+
+ public static String formatNumber(double number) {
+ return formatter == null ? "" + number : formatter.format(number);
+ }
+}
diff --git a/src/main/java/com/artillexstudios/axtrade/utils/SoundUtils.java b/src/main/java/com/artillexstudios/axtrade/utils/SoundUtils.java
new file mode 100644
index 0000000..ba6ccbf
--- /dev/null
+++ b/src/main/java/com/artillexstudios/axtrade/utils/SoundUtils.java
@@ -0,0 +1,28 @@
+package com.artillexstudios.axtrade.utils;
+
+import com.artillexstudios.axapi.utils.StringUtils;
+import net.kyori.adventure.key.InvalidKeyException;
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.sound.Sound;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.artillexstudios.axtrade.AxTrade.BUKKITAUDIENCES;
+import static com.artillexstudios.axtrade.AxTrade.LANG;
+
+public class SoundUtils {
+
+ public static void playSound(@NotNull Player player, @Nullable String route) {
+ if (route == null) return;
+ if (LANG.getString("sounds." + route, "").isBlank()) return;
+
+ try {
+ final Sound sound = Sound.sound().type(Key.key(LANG.getString("sounds." + route))).build();
+ BUKKITAUDIENCES.player(player).playSound(sound);
+ } catch (InvalidKeyException ex) {
+ Bukkit.getConsoleSender().sendMessage(StringUtils.formatToString("FFFFAA[AxAuctions] The sound %sound% does not exist, section: %section%!".replace("%sound%", LANG.getString("sounds." + route)).replace("%section%", route)));
+ }
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 3d8962c..afcf009 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -9,5 +9,28 @@ command-aliases:
# the time after clicking the trade confirm button before the trade finishes
trade-confirm-seconds: 10
+# how fast should trade requests expire?
+trade-request-expire-seconds: 60
+
+# how far can 2 people be to trade?
+# set to -1 to disable
+trade-max-distance: 10
+
+number-formatting:
+ # modes:
+ # 0 - formatted (customizable, look at the formatted part)
+ # 1 - short (1K)
+ # 2 - raw (1000.4242421412)
+ mode: 0
+ # https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
+ formatted: "#,###.##"
+ # format: language_COUNTRY
+ short: "en_US"
+
+# list of gamemodes: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/GameMode.html
+# you can't use the trade in these gamemodes
+disallowed-gamemodes:
+ - SPECTATOR
+
# do not change this
version: 1
\ No newline at end of file
diff --git a/src/main/resources/currencies.yml b/src/main/resources/currencies.yml
new file mode 100644
index 0000000..1ae7b0f
--- /dev/null
+++ b/src/main/resources/currencies.yml
@@ -0,0 +1,47 @@
+# you can create your own currencies by using placeholders
+# make sure that none of the placeholders have any formatting on them
+# requires PlaceholderAPI
+placeholder-currencies:
+ Example-Currency:
+ register: false
+ # if the currency uses whole numbers then disable this
+ # 100.5 - true
+ # 100 - false
+ uses-double: true
+ # if the placeholder gets parsed even for offline players, enable this
+ works-offline: false
+ settings:
+ raw-placeholder: "%vault_eco_balance_fixed%"
+ give-command: "eco give %player% %amount%"
+ take-command: "eco take %player% %amount%"
+
+currencies:
+ Experience:
+ register: true
+ Vault:
+ register: true
+ PlayerPoints:
+ register: true
+ RoyaleEconomy:
+ register: true
+ CoinsEngine:
+ register: true
+ currency-name: "coins"
+ UltraEconomy:
+ register: true
+ currency-name: "coins"
+ KingdomsX:
+ register: true
+ RivalHarvesterHoes:
+ register: true
+ SuperMobCoins:
+ register: true
+ TheOnly-MobCoins:
+ register: true
+ TokenManager:
+ register: true
+ AxQuestBoard:
+ register: true
+
+# do not change this
+version: 5
\ No newline at end of file
diff --git a/src/main/resources/guis.yml b/src/main/resources/guis.yml
index 7307e02..b9787bf 100644
--- a/src/main/resources/guis.yml
+++ b/src/main/resources/guis.yml
@@ -45,27 +45,29 @@ own:
- " &7- &fDo you want to change something?"
- ""
- "ffdd&l> ffddClick &8- ffddCancel Confirmation"
- # you can define as many currencies as you want, also make sure to copy them to the 'partner' section!
+ # you can define as many currencies as you want, but make sure to copy them to the 'partner' section too!
currency1:
slot: 2
# you need Vault installed for this
- currency: "vault:money"
+ currency: "Vault"
material: "GOLD_NUGGET"
name: "ffdd&lᴍᴏɴᴇʏ"
lore:
+ - "&7Your offer"
- ""
- - " &7- &fAmount:"
+ - " &7- &fAmount: ffdd%amount%$"
- ""
- "ffdd&l> ffddClick &8- ffddChange Amount"
currency2:
slot: 3
# you need Vault installed for this
- currency: "vanilla:experience"
+ currency: "Experience"
material: "EXPERIENCE_BOTTLE"
name: "ffdd&lᴇxᴘᴇʀɪᴇɴᴄᴇ"
lore:
+ - "&7Your offer"
- ""
- - " &7- &fAmount:"
+ - " &7- &fAmount: ffdd%amount% EXP"
- ""
- "ffdd&l> ffddClick &8- ffddChange Amount"
@@ -88,24 +90,24 @@ partner:
- " &7- &fThe other player has confirmed the trade!"
currency1:
slot: 6
- # you need Vault installed for this
- currency: "vault:money"
+ currency: "Vault"
material: "GOLD_NUGGET"
name: "ffdd&lᴍᴏɴᴇʏ"
lore:
+ - "&7%player%'s offer"
- ""
- - " &7- &fAmount:"
+ - " &7- &fAmount: ffdd%amount%$"
- ""
- "ffdd&l> ffddClick &8- ffddChange Amount"
currency2:
slot: 5
- # you need Vault installed for this
- currency: "vanilla:experience"
+ currency: "Experience"
material: "EXPERIENCE_BOTTLE"
name: "ffdd&lᴇxᴘᴇʀɪᴇɴᴄᴇ"
lore:
+ - "&7%player%'s offer"
- ""
- - " &7- &fAmount:"
+ - " &7- &fAmount: ffdd%amount% EXP"
- ""
- "ffdd&l> ffddClick &8- ffddChange Amount"
diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml
index c60268d..4c37911 100644
--- a/src/main/resources/lang.yml
+++ b/src/main/resources/lang.yml
@@ -15,9 +15,52 @@ reload:
success: "!FF33Plugin successfully reloaded!"
failed: "FF3333Failed to reload the plugin! Something is wrong in the &f%file%FF3333 file, look in the console or use a yaml validator to fix the errors!"
-trade-started: "CCFFEEYou have started a trade with FFDD%player%CCFFEE!"
-trade-aborted: "CCFFEEYour trade with FFDD%player% CCFFEEwas aborted!"
-trade-completed: "CCFFEEYour trade with FFDD%player% CCFFEEwas completed!"
+trade:
+ started: "CCFFEEYou have started a trade with FFDD%player%CCFFEE!"
+ completed: "CCFFEEYour trade with FFDD%player% CCFFEEwas completed!"
+ aborted: "CCFFEEYour trade with FFDD%player% CCFFEEwas aborted!"
+
+currency-editor:
+ success: "CCFFEESuccessfully changed value!"
+ failed: "CCFFEEIncorrect value!"
+ not-enough: "CCFFEEYou don't have enough of this currency!"
+
+request:
+ sent-sender: "CCFFEEYou have successfully sent a trade request to FFDD%player%CCFFEE!"
+ sent-receiver: |
+ CCFFEEYou have received a trade request from FFDD%player%CCFFEE!
+ FF00/trade accept %player%
+ FF0000/trade deny %player%
+ no-request: "CCFFEEYou don't have an active trade request from FFDD%player%CCFFEE!"
+ deny-sender: "CCFFEEYou trade request was denied by FFDD%player%CCFFEE!"
+ deny-receiver: "CCFFEEYou have successfully denied FFDD%player%CCFFEE's trade request!"
+ cant-trade-self: "CCFFEEYou can't send a trade request to yourself!"
+ already-in-trade: "CCFFEEThe player is already trading with someone!"
+ already-sent: "CCFFEEYou have already sent a trade request to FFDD%player%CCFFEE!"
+ too-far: "CCFFEEYou are too far from FFDD%player% CCFFEEto send a trade request!"
+
+# this must be 4 lines
+# note: currently the first line must be left empty
+currency-editor-sign:
+ - ""
+ - "-----------"
+ - "Write the new value"
+ - "in the first line"
+
+# list of sounds: https://www.digminecraft.com/lists/sound_list_pc.php
+# set to "" to disable
+sounds:
+ # trade sounds
+ started: "entity.player.levelup"
+ completed: "entity.player.levelup"
+ aborted: "block.anvil.destroy"
+ # trade requests
+ deny: "block.anvil.land"
+ requested: "entity.experience_bottle.throw"
+ # gui sounds
+ accept: "ui.button.click"
+ countdown: "ui.button.click"
+ cancel: "ui.button.click"
# do not change this
version: 1
\ No newline at end of file