From ac78d4cac6cb1305189af3f0e1e93abc1c3a88a6 Mon Sep 17 00:00:00 2001 From: Xelara Networks Date: Sun, 14 Jun 2026 15:39:56 -0400 Subject: [PATCH] yep --- README.md | 0 pom.xml | 47 ++ .../yourname/dirttrades/DirtTradesPlugin.java | 44 ++ .../com/yourname/dirttrades/TradeCommand.java | 112 +++++ .../yourname/dirttrades/TradeListener.java | 182 ++++++++ .../com/yourname/dirttrades/TradeManager.java | 406 ++++++++++++++++++ .../com/yourname/dirttrades/TradeSession.java | 252 +++++++++++ src/main/resources/config.yml | 131 ++++++ src/main/resources/plugin.yml | 25 ++ target/DirtTrades-1.0-SNAPSHOT.jar | Bin 0 -> 23041 bytes .../dirttrades/DirtTradesPlugin.class | Bin 0 -> 2046 bytes .../yourname/dirttrades/TradeCommand.class | Bin 0 -> 3966 bytes .../yourname/dirttrades/TradeListener$1.class | Bin 0 -> 762 bytes .../yourname/dirttrades/TradeListener.class | Bin 0 -> 7544 bytes .../TradeManager$TradeRequest.class | Bin 0 -> 652 bytes .../yourname/dirttrades/TradeManager.class | Bin 0 -> 14908 bytes .../yourname/dirttrades/TradeSession.class | Bin 0 -> 9811 bytes target/classes/config.yml | 131 ++++++ target/classes/plugin.yml | 25 ++ target/maven-archiver/pom.properties | 5 + .../compile/default-compile/createdFiles.lst | 7 + .../compile/default-compile/inputFiles.lst | 5 + 22 files changed, 1372 insertions(+) create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/com/yourname/dirttrades/DirtTradesPlugin.java create mode 100644 src/main/java/com/yourname/dirttrades/TradeCommand.java create mode 100644 src/main/java/com/yourname/dirttrades/TradeListener.java create mode 100644 src/main/java/com/yourname/dirttrades/TradeManager.java create mode 100644 src/main/java/com/yourname/dirttrades/TradeSession.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/plugin.yml create mode 100644 target/DirtTrades-1.0-SNAPSHOT.jar create mode 100644 target/classes/com/yourname/dirttrades/DirtTradesPlugin.class create mode 100644 target/classes/com/yourname/dirttrades/TradeCommand.class create mode 100644 target/classes/com/yourname/dirttrades/TradeListener$1.class create mode 100644 target/classes/com/yourname/dirttrades/TradeListener.class create mode 100644 target/classes/com/yourname/dirttrades/TradeManager$TradeRequest.class create mode 100644 target/classes/com/yourname/dirttrades/TradeManager.class create mode 100644 target/classes/com/yourname/dirttrades/TradeSession.class create mode 100644 target/classes/config.yml create mode 100644 target/classes/plugin.yml create mode 100644 target/maven-archiver/pom.properties create mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..218212f --- /dev/null +++ b/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + + com.yourname + DirtTrades + 1.0-SNAPSHOT + jar + + DirtTrades + + + 21 + UTF-8 + 21 + + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + + + + io.papermc.paper + paper-api + 1.21.1-R0.1-SNAPSHOT + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 21 + + + + + diff --git a/src/main/java/com/yourname/dirttrades/DirtTradesPlugin.java b/src/main/java/com/yourname/dirttrades/DirtTradesPlugin.java new file mode 100644 index 0000000..845740d --- /dev/null +++ b/src/main/java/com/yourname/dirttrades/DirtTradesPlugin.java @@ -0,0 +1,44 @@ +package com.yourname.dirttrades; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; + +public class DirtTradesPlugin extends JavaPlugin { + + private TradeManager tradeManager; + + @Override + public void onEnable() { + saveDefaultConfig(); + + this.tradeManager = new TradeManager(this); + + TradeCommand tradeCommand = new TradeCommand(this, tradeManager); + getCommand("trade").setExecutor(tradeCommand); + getCommand("trade").setTabCompleter(tradeCommand); + + Bukkit.getPluginManager().registerEvents(new TradeListener(this, tradeManager), this); + + getLogger().info("DirtTrades enabled."); + } + + @Override + public void onDisable() { + if (tradeManager != null) { + tradeManager.shutdown(); + } + + getLogger().info("DirtTrades disabled."); + } + + public TradeManager getTradeManager() { + return tradeManager; + } + + public void reloadPlugin() { + reloadConfig(); + if (tradeManager != null) { + tradeManager.reload(); + } + } +} diff --git a/src/main/java/com/yourname/dirttrades/TradeCommand.java b/src/main/java/com/yourname/dirttrades/TradeCommand.java new file mode 100644 index 0000000..8ac090a --- /dev/null +++ b/src/main/java/com/yourname/dirttrades/TradeCommand.java @@ -0,0 +1,112 @@ +package com.yourname.dirttrades; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TradeCommand implements CommandExecutor, TabCompleter { + + private final DirtTradesPlugin plugin; + private final TradeManager tradeManager; + + public TradeCommand(DirtTradesPlugin plugin, TradeManager tradeManager) { + this.plugin = plugin; + this.tradeManager = tradeManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player player)) { + if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { + if (!sender.hasPermission("dirttrades.reload") && !sender.hasPermission("dirttrades.admin")) { + sender.sendMessage(tradeManager.msg("no-permission")); + return true; + } + + plugin.reloadPlugin(); + sender.sendMessage(tradeManager.msg("config-reloaded")); + return true; + } + + sender.sendMessage(tradeManager.msg("player-only")); + return true; + } + + if (!player.hasPermission("dirttrades.use") && !player.hasPermission("dirttrades.admin")) { + player.sendMessage(tradeManager.msg("no-permission")); + return true; + } + + if (args.length == 0) { + player.sendMessage(tradeManager.msg("usage")); + return true; + } + + String sub = args[0]; + + if (sub.equalsIgnoreCase("accept")) { + tradeManager.acceptRequest(player); + return true; + } + + if (sub.equalsIgnoreCase("deny")) { + tradeManager.denyRequest(player); + return true; + } + + if (sub.equalsIgnoreCase("reload")) { + if (!player.hasPermission("dirttrades.reload") && !player.hasPermission("dirttrades.admin")) { + player.sendMessage(tradeManager.msg("no-permission")); + return true; + } + + plugin.reloadPlugin(); + player.sendMessage(tradeManager.msg("config-reloaded")); + return true; + } + + Player target = Bukkit.getPlayerExact(sub); + if (target == null || !target.isOnline()) { + player.sendMessage(tradeManager.msg("player-not-found")); + return true; + } + + tradeManager.sendTradeRequest(player, target); + return true; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if (args.length == 1) { + List options = new ArrayList<>(); + options.add("accept"); + options.add("deny"); + if (sender.hasPermission("dirttrades.reload") || sender.hasPermission("dirttrades.admin")) { + options.add("reload"); + } + + for (Player player : Bukkit.getOnlinePlayers()) { + options.add(player.getName()); + } + + String input = args[0].toLowerCase(); + List matches = new ArrayList<>(); + for (String option : options) { + if (option.toLowerCase().startsWith(input)) { + matches.add(option); + } + } + Collections.sort(matches); + return matches; + } + + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/yourname/dirttrades/TradeListener.java b/src/main/java/com/yourname/dirttrades/TradeListener.java new file mode 100644 index 0000000..f6519df --- /dev/null +++ b/src/main/java/com/yourname/dirttrades/TradeListener.java @@ -0,0 +1,182 @@ +package com.yourname.dirttrades; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.scheduler.BukkitTask; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class TradeListener implements Listener { + + private final DirtTradesPlugin plugin; + private final TradeManager manager; + private final Set closingPlayers = new HashSet<>(); + private BukkitTask rangeTask; + + public TradeListener(DirtTradesPlugin plugin, TradeManager manager) { + this.plugin = plugin; + this.manager = manager; + startRangeTask(); + } + + private void startRangeTask() { + rangeTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> { + Set checked = new HashSet<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + TradeSession session = manager.getSession(player); + if (session == null || checked.contains(session)) { + continue; + } + + checked.add(session); + if (session.shouldCancelForDistance()) { + manager.cancelTrade(session, null, false); + + Player p1 = Bukkit.getPlayer(session.getPlayer1()); + Player p2 = Bukkit.getPlayer(session.getPlayer2()); + + if (p1 != null && p1.isOnline()) { + p1.sendMessage(manager.msg("too-far")); + } + if (p2 != null && p2.isOnline()) { + p2.sendMessage(manager.msg("too-far")); + } + } + } + }, 20L, 20L); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryClick(InventoryClickEvent event) { + if (!(event.getWhoClicked() instanceof Player player)) { + return; + } + + TradeSession session = manager.getSession(player); + if (session == null) { + return; + } + + Inventory top = event.getView().getTopInventory(); + if (!top.equals(session.getInventory())) { + return; + } + + int rawSlot = event.getRawSlot(); + + if (rawSlot < top.getSize()) { + if (session.isOfferSlot(player, rawSlot)) { + session.resetAccepts(); + return; + } + + if (session.isAnyButtonSlot(rawSlot)) { + event.setCancelled(true); + session.handleButtonClick(player, rawSlot); + return; + } + + event.setCancelled(true); + return; + } + + InventoryAction action = event.getAction(); + switch (action) { + case MOVE_TO_OTHER_INVENTORY -> event.setCancelled(true); + default -> { + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryClose(InventoryCloseEvent event) { + if (!(event.getPlayer() instanceof Player player)) { + return; + } + + TradeSession session = manager.getSession(player); + if (session == null) { + return; + } + + if (!event.getInventory().equals(session.getInventory())) { + return; + } + + if (session.isClosing()) { + return; + } + + if (closingPlayers.contains(player.getUniqueId())) { + return; + } + + closingPlayers.add(player.getUniqueId()); + Bukkit.getScheduler().runTask(plugin, () -> { + try { + TradeSession latest = manager.getSession(player); + if (latest != null && latest == session && !latest.isClosing()) { + manager.cancelTrade(latest, player.getUniqueId(), false); + } + } finally { + closingPlayers.remove(player.getUniqueId()); + } + }); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + TradeSession session = manager.getSession(player); + if (session != null) { + manager.cancelTrade(session, player.getUniqueId(), true); + } + } + + @EventHandler(ignoreCancelled = true) + public void onMove(PlayerMoveEvent event) { + if (!plugin.getConfig().getBoolean("settings.close-on-move-out-of-range", false)) { + return; + } + + if (event.getTo() == null) { + return; + } + + if (event.getFrom().getBlockX() == event.getTo().getBlockX() + && event.getFrom().getBlockY() == event.getTo().getBlockY() + && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + return; + } + + TradeSession session = manager.getSession(event.getPlayer()); + if (session == null) { + return; + } + + if (session.shouldCancelForDistance()) { + manager.cancelTrade(session, event.getPlayer().getUniqueId(), false); + + Player p1 = Bukkit.getPlayer(session.getPlayer1()); + Player p2 = Bukkit.getPlayer(session.getPlayer2()); + + if (p1 != null && p1.isOnline()) { + p1.sendMessage(manager.msg("too-far")); + } + if (p2 != null && p2.isOnline()) { + p2.sendMessage(manager.msg("too-far")); + } + } + } +} diff --git a/src/main/java/com/yourname/dirttrades/TradeManager.java b/src/main/java/com/yourname/dirttrades/TradeManager.java new file mode 100644 index 0000000..5b65b7f --- /dev/null +++ b/src/main/java/com/yourname/dirttrades/TradeManager.java @@ -0,0 +1,406 @@ +package com.yourname.dirttrades; + +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.scheduler.BukkitTask; + +import java.util.*; + +public class TradeManager { + + private final DirtTradesPlugin plugin; + + private final Map pendingRequests = new HashMap<>(); + private final Map activeTrades = new HashMap<>(); + + public TradeManager(DirtTradesPlugin plugin) { + this.plugin = plugin; + } + + public void reload() { + for (TradeRequest request : new ArrayList<>(pendingRequests.values())) { + if (request.expireTask != null) { + request.expireTask.cancel(); + } + } + pendingRequests.clear(); + + for (TradeSession session : new HashSet<>(activeTrades.values())) { + cancelTrade(session, null, true); + } + + activeTrades.clear(); + } + + public void shutdown() { + reload(); + } + + public void sendTradeRequest(Player sender, Player target) { + if (plugin.getConfig().getBoolean("settings.prevent-self-trade", true) + && sender.getUniqueId().equals(target.getUniqueId())) { + sender.sendMessage(msg("cannot-trade-self")); + return; + } + + if (!target.hasPermission("dirttrades.use") && !target.hasPermission("dirttrades.admin")) { + sender.sendMessage(msg("target-no-permission")); + return; + } + + if (plugin.getConfig().getBoolean("settings.block-creative-mode-trading", true)) { + if (sender.getGameMode() == GameMode.CREATIVE || target.getGameMode() == GameMode.CREATIVE) { + sender.sendMessage(msg("creative-blocked")); + return; + } + } + + if (hasPendingRequestBetween(sender.getUniqueId(), target.getUniqueId())) { + sender.sendMessage(msg("already-in-trade")); + return; + } + + if (isBusy(sender.getUniqueId()) || isBusy(target.getUniqueId())) { + sender.sendMessage(msg("already-in-trade")); + return; + } + + TradeRequest existing = pendingRequests.remove(target.getUniqueId()); + if (existing != null && existing.expireTask != null) { + existing.expireTask.cancel(); + } + + int expireSeconds = plugin.getConfig().getInt("settings.request-expire-seconds", 30); + TradeRequest request = new TradeRequest(sender.getUniqueId(), target.getUniqueId()); + + request.expireTask = Bukkit.getScheduler().runTaskLater(plugin, () -> { + TradeRequest current = pendingRequests.get(target.getUniqueId()); + if (current != null && current.sender.equals(sender.getUniqueId())) { + pendingRequests.remove(target.getUniqueId()); + + Player onlineSender = Bukkit.getPlayer(sender.getUniqueId()); + Player onlineTarget = Bukkit.getPlayer(target.getUniqueId()); + + if (onlineSender != null && onlineSender.isOnline()) { + onlineSender.sendMessage(msg("request-expired-sender") + .replace("%target%", target.getName())); + } + if (onlineTarget != null && onlineTarget.isOnline()) { + onlineTarget.sendMessage(msg("request-expired-target") + .replace("%sender%", sender.getName())); + } + } + }, expireSeconds * 20L); + + pendingRequests.put(target.getUniqueId(), request); + + sender.sendMessage(msg("request-sent").replace("%target%", target.getName())); + target.sendMessage(msg("request-received").replace("%sender%", sender.getName())); + target.sendMessage(msg("request-received-hover")); + + playSound(sender, Sound.UI_BUTTON_CLICK); + playSound(target, Sound.UI_BUTTON_CLICK); + } + + public void acceptRequest(Player target) { + TradeRequest request = pendingRequests.remove(target.getUniqueId()); + if (request == null) { + target.sendMessage(msg("no-pending-request")); + return; + } + + if (request.expireTask != null) { + request.expireTask.cancel(); + } + + Player sender = Bukkit.getPlayer(request.sender); + if (sender == null || !sender.isOnline()) { + target.sendMessage(msg("player-not-found")); + return; + } + + if (plugin.getConfig().getBoolean("settings.block-creative-mode-trading", true)) { + if (sender.getGameMode() == GameMode.CREATIVE || target.getGameMode() == GameMode.CREATIVE) { + target.sendMessage(msg("creative-blocked")); + return; + } + } + + if (isBusy(sender.getUniqueId()) || isBusy(target.getUniqueId())) { + target.sendMessage(msg("already-in-trade")); + return; + } + + target.sendMessage(msg("request-accepted").replace("%sender%", sender.getName())); + sender.sendMessage(msg("trade-started").replace("%player%", target.getName())); + target.sendMessage(msg("trade-started").replace("%player%", sender.getName())); + + startTrade(sender, target); + } + + public void denyRequest(Player target) { + TradeRequest request = pendingRequests.remove(target.getUniqueId()); + if (request == null) { + target.sendMessage(msg("no-pending-request")); + return; + } + + if (request.expireTask != null) { + request.expireTask.cancel(); + } + + Player sender = Bukkit.getPlayer(request.sender); + target.sendMessage(msg("request-denied").replace("%sender%", sender != null ? sender.getName() : "Unknown")); + + if (sender != null && sender.isOnline()) { + sender.sendMessage(msg("request-denied-sender").replace("%target%", target.getName())); + } + } + + public void startTrade(Player player1, Player player2) { + TradeSession session = new TradeSession(plugin, this, player1.getUniqueId(), player2.getUniqueId()); + activeTrades.put(player1.getUniqueId(), session); + activeTrades.put(player2.getUniqueId(), session); + session.open(); + } + + public boolean isBusy(UUID uuid) { + if (activeTrades.containsKey(uuid)) { + return true; + } + + for (TradeRequest request : pendingRequests.values()) { + if (request.sender.equals(uuid) || request.target.equals(uuid)) { + return true; + } + } + + return false; + } + + private boolean hasPendingRequestBetween(UUID a, UUID b) { + for (TradeRequest request : pendingRequests.values()) { + if ((request.sender.equals(a) && request.target.equals(b)) + || (request.sender.equals(b) && request.target.equals(a))) { + return true; + } + } + return false; + } + + public TradeSession getSession(Player player) { + return activeTrades.get(player.getUniqueId()); + } + + public void removeSession(TradeSession session) { + activeTrades.remove(session.getPlayer1()); + activeTrades.remove(session.getPlayer2()); + } + + public void cancelTrade(TradeSession session, UUID cancelledBy, boolean silent) { + session.returnItemsToOwners(); + removeSession(session); + + Player p1 = Bukkit.getPlayer(session.getPlayer1()); + Player p2 = Bukkit.getPlayer(session.getPlayer2()); + + clearActionBar(p1); + clearActionBar(p2); + + if (p1 != null && p1.isOnline() && p1.getOpenInventory().getTopInventory().equals(session.getInventory())) { + p1.closeInventory(); + } + if (p2 != null && p2.isOnline() && p2.getOpenInventory().getTopInventory().equals(session.getInventory())) { + p2.closeInventory(); + } + + if (!silent) { + if (p1 != null && p1.isOnline()) { + if (cancelledBy != null && cancelledBy.equals(p1.getUniqueId())) { + p1.sendMessage(msg("trade-cancelled")); + } else { + p1.sendMessage(msg("trade-cancelled-other")); + } + } + + if (p2 != null && p2.isOnline()) { + if (cancelledBy != null && cancelledBy.equals(p2.getUniqueId())) { + p2.sendMessage(msg("trade-cancelled")); + } else { + p2.sendMessage(msg("trade-cancelled-other")); + } + } + } + } + + public void completeTrade(TradeSession session) { + Player p1 = Bukkit.getPlayer(session.getPlayer1()); + Player p2 = Bukkit.getPlayer(session.getPlayer2()); + + if (p1 == null || p2 == null) { + cancelTrade(session, null, true); + return; + } + + List p1Items = session.collectPlayer1Items(); + List p2Items = session.collectPlayer2Items(); + + giveItems(p1, p2Items); + giveItems(p2, p1Items); + + removeSession(session); + + clearActionBar(p1); + clearActionBar(p2); + + if (p1.getOpenInventory().getTopInventory().equals(session.getInventory())) { + p1.closeInventory(); + } + if (p2.getOpenInventory().getTopInventory().equals(session.getInventory())) { + p2.closeInventory(); + } + + p1.sendMessage(msg("trade-completed")); + p2.sendMessage(msg("trade-completed")); + + playSound(p1, Sound.ENTITY_PLAYER_LEVELUP); + playSound(p2, Sound.ENTITY_PLAYER_LEVELUP); + } + + private void giveItems(Player player, List items) { + boolean droppedAny = false; + + for (ItemStack item : items) { + if (item == null || item.getType().isAir()) { + continue; + } + + HashMap leftover = player.getInventory().addItem(item); + if (!leftover.isEmpty()) { + for (ItemStack left : leftover.values()) { + if (plugin.getConfig().getBoolean("settings.drop-items-if-inventory-full", true)) { + player.getWorld().dropItemNaturally(player.getLocation(), left); + droppedAny = true; + } + } + } + } + + if (droppedAny) { + player.sendMessage(msg("inventory-full-drop")); + } + } + + public void sendWaitingActionBars(TradeSession session, boolean player1Accepted, boolean player2Accepted) { + if (!plugin.getConfig().getBoolean("settings.actionbar-enabled", true)) { + return; + } + + Player p1 = Bukkit.getPlayer(session.getPlayer1()); + Player p2 = Bukkit.getPlayer(session.getPlayer2()); + + if (p1 == null || p2 == null) { + return; + } + + if (player1Accepted && !player2Accepted) { + sendActionBar(p1, rawMessage("actionbar-waiting-self")); + sendActionBar(p2, rawMessage("actionbar-waiting-other")); + return; + } + + if (!player1Accepted && player2Accepted) { + sendActionBar(p2, rawMessage("actionbar-waiting-self")); + sendActionBar(p1, rawMessage("actionbar-waiting-other")); + return; + } + + clearActionBar(p1); + clearActionBar(p2); + } + + public void clearActionBar(Player player) { + if (player == null || !player.isOnline()) { + return; + } + + player.sendActionBar(Component.text(color(plugin.getConfig().getString("messages.actionbar-cleared", "")))); + } + + public void sendActionBar(Player player, String message) { + if (player == null || !player.isOnline()) { + return; + } + + player.sendActionBar(Component.text(color(message))); + } + + public String rawMessage(String path) { + return plugin.getConfig().getString("messages." + path, ""); + } + + public String msg(String path) { + String prefix = color(plugin.getConfig().getString("messages.prefix", "&6[DirtTrades] &r")); + String text = color(plugin.getConfig().getString("messages." + path, "&cMissing message: " + path)); + return prefix + text; + } + + public String color(String text) { + return text == null ? "" : text.replace("&", "ยง"); + } + + public ItemStack createConfiguredItem(String path) { + ConfigurationSection section = plugin.getConfig().getConfigurationSection("items." + path); + if (section == null) { + return new ItemStack(Material.BARRIER); + } + + Material material = Material.matchMaterial(section.getString("material", "BARRIER")); + if (material == null) { + material = Material.BARRIER; + } + + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.displayName(Component.text(color(section.getString("name", path)))); + List loreLines = section.getStringList("lore"); + if (!loreLines.isEmpty()) { + List lore = new ArrayList<>(); + for (String line : loreLines) { + lore.add(Component.text(color(line))); + } + meta.lore(lore); + } + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + item.setItemMeta(meta); + } + + return item; + } + + public void playSound(Player player, Sound sound) { + if (plugin.getConfig().getBoolean("settings.sound-enabled", true)) { + player.playSound(player.getLocation(), sound, 1f, 1f); + } + } + + private static class TradeRequest { + private final UUID sender; + private final UUID target; + private BukkitTask expireTask; + + private TradeRequest(UUID sender, UUID target) { + this.sender = sender; + this.target = target; + } + } +} diff --git a/src/main/java/com/yourname/dirttrades/TradeSession.java b/src/main/java/com/yourname/dirttrades/TradeSession.java new file mode 100644 index 0000000..05db5d0 --- /dev/null +++ b/src/main/java/com/yourname/dirttrades/TradeSession.java @@ -0,0 +1,252 @@ +package com.yourname.dirttrades; + +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class TradeSession { + + private final DirtTradesPlugin plugin; + private final TradeManager manager; + private final UUID player1; + private final UUID player2; + private final Inventory inventory; + + private boolean player1Accepted = false; + private boolean player2Accepted = false; + private boolean closing = false; + + public TradeSession(DirtTradesPlugin plugin, TradeManager manager, UUID player1, UUID player2) { + this.plugin = plugin; + this.manager = manager; + this.player1 = player1; + this.player2 = player2; + + String p1Name = Bukkit.getOfflinePlayer(player1).getName(); + String p2Name = Bukkit.getOfflinePlayer(player2).getName(); + String title = manager.color(plugin.getConfig().getString("gui.title", "&8Trade: %player1% &7<-> &f%player2%")) + .replace("%player1%", p1Name == null ? "Player1" : p1Name) + .replace("%player2%", p2Name == null ? "Player2" : p2Name); + + int size = plugin.getConfig().getInt("gui.size", 54); + this.inventory = Bukkit.createInventory(null, size, Component.text(title)); + + refreshButtons(); + } + + public void open() { + Player p1 = Bukkit.getPlayer(player1); + Player p2 = Bukkit.getPlayer(player2); + + if (p1 == null || p2 == null) { + manager.cancelTrade(this, null, true); + return; + } + + refreshButtons(); + p1.openInventory(inventory); + p2.openInventory(inventory); + manager.clearActionBar(p1); + manager.clearActionBar(p2); + } + + public Inventory getInventory() { + return inventory; + } + + public UUID getPlayer1() { + return player1; + } + + public UUID getPlayer2() { + return player2; + } + + public boolean isClosing() { + return closing; + } + + public boolean isPlayer1(Player player) { + return player.getUniqueId().equals(player1); + } + + public boolean isPlayer2(Player player) { + return player.getUniqueId().equals(player2); + } + + public boolean isOfferSlot(Player player, int slot) { + if (isPlayer1(player)) { + return plugin.getConfig().getIntegerList("gui.player1-slots").contains(slot); + } + if (isPlayer2(player)) { + return plugin.getConfig().getIntegerList("gui.player2-slots").contains(slot); + } + return false; + } + + public boolean isAnyButtonSlot(int slot) { + return slot == plugin.getConfig().getInt("gui.accept-slot", 22) + || slot == plugin.getConfig().getInt("gui.decline-slot", 31); + } + + public void handleButtonClick(Player player, int slot) { + int acceptSlot = plugin.getConfig().getInt("gui.accept-slot", 22); + int declineSlot = plugin.getConfig().getInt("gui.decline-slot", 31); + + if (slot == acceptSlot) { + if (isPlayer1(player)) { + player1Accepted = true; + } else if (isPlayer2(player)) { + player2Accepted = true; + } + + manager.playSound(player, Sound.UI_BUTTON_CLICK); + refreshButtons(); + manager.sendWaitingActionBars(this, player1Accepted, player2Accepted); + tryComplete(); + return; + } + + if (slot == declineSlot) { + manager.cancelTrade(this, player.getUniqueId(), false); + } + } + + public void resetAccepts() { + if (!player1Accepted && !player2Accepted) { + return; + } + + player1Accepted = false; + player2Accepted = false; + refreshButtons(); + manager.sendWaitingActionBars(this, player1Accepted, player2Accepted); + } + + private void tryComplete() { + if (player1Accepted && player2Accepted) { + closing = true; + manager.completeTrade(this); + } + } + + public void refreshButtons() { + for (int slot : plugin.getConfig().getIntegerList("gui.divider-slots")) { + inventory.setItem(slot, manager.createConfiguredItem("divider")); + } + + int acceptSlot = plugin.getConfig().getInt("gui.accept-slot", 22); + int declineSlot = plugin.getConfig().getInt("gui.decline-slot", 31); + + if (player1Accepted || player2Accepted) { + inventory.setItem(acceptSlot, manager.createConfiguredItem("accepted")); + } else { + inventory.setItem(acceptSlot, manager.createConfiguredItem("accept")); + } + + inventory.setItem(declineSlot, manager.createConfiguredItem("decline")); + } + + public void returnItemsToOwners() { + List p1Items = collectPlayer1Items(); + List p2Items = collectPlayer2Items(); + + Player p1 = Bukkit.getPlayer(player1); + Player p2 = Bukkit.getPlayer(player2); + + if (p1 != null && p1.isOnline()) { + giveBack(p1, p1Items); + } + + if (p2 != null && p2.isOnline()) { + giveBack(p2, p2Items); + } + + clearOfferSlots(); + } + + private void giveBack(Player player, List items) { + boolean droppedAny = false; + + for (ItemStack item : items) { + if (item == null || item.getType().isAir()) { + continue; + } + + var leftover = player.getInventory().addItem(item); + if (!leftover.isEmpty()) { + for (ItemStack left : leftover.values()) { + if (plugin.getConfig().getBoolean("settings.drop-items-if-inventory-full", true)) { + player.getWorld().dropItemNaturally(player.getLocation(), left); + droppedAny = true; + } + } + } + } + + if (droppedAny) { + player.sendMessage(manager.msg("inventory-full-drop")); + } + } + + public List collectPlayer1Items() { + List items = new ArrayList<>(); + for (int slot : plugin.getConfig().getIntegerList("gui.player1-slots")) { + ItemStack item = inventory.getItem(slot); + if (item != null && !item.getType().isAir()) { + items.add(item.clone()); + } + } + return items; + } + + public List collectPlayer2Items() { + List items = new ArrayList<>(); + for (int slot : plugin.getConfig().getIntegerList("gui.player2-slots")) { + ItemStack item = inventory.getItem(slot); + if (item != null && !item.getType().isAir()) { + items.add(item.clone()); + } + } + return items; + } + + public void clearOfferSlots() { + for (int slot : plugin.getConfig().getIntegerList("gui.player1-slots")) { + inventory.setItem(slot, new ItemStack(Material.AIR)); + } + for (int slot : plugin.getConfig().getIntegerList("gui.player2-slots")) { + inventory.setItem(slot, new ItemStack(Material.AIR)); + } + } + + public boolean shouldCancelForDistance() { + if (!plugin.getConfig().getBoolean("settings.close-on-move-out-of-range", false)) { + return false; + } + + Player p1 = Bukkit.getPlayer(player1); + Player p2 = Bukkit.getPlayer(player2); + if (p1 == null || p2 == null) { + return true; + } + + if (!p1.getWorld().equals(p2.getWorld())) { + return true; + } + + Location l1 = p1.getLocation(); + Location l2 = p2.getLocation(); + double max = plugin.getConfig().getDouble("settings.max-trade-distance", 10.0); + return l1.distanceSquared(l2) > (max * max); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..85a8b60 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,131 @@ +settings: + request-expire-seconds: 30 + prevent-self-trade: true + block-creative-mode-trading: true + close-on-move-out-of-range: false + max-trade-distance: 10.0 + drop-items-if-inventory-full: true + sound-enabled: true + actionbar-enabled: true + +gui: + title: "&8Dirt Trade: %player1% &7<-> &f%player2%" + size: 54 + + divider-slots: + - 4 + - 13 + - 40 + - 49 + + player1-slots: + - 0 + - 1 + - 2 + - 3 + - 9 + - 10 + - 11 + - 12 + - 18 + - 19 + - 20 + - 21 + - 27 + - 28 + - 29 + - 30 + - 36 + - 37 + - 38 + - 39 + - 45 + - 46 + - 47 + - 48 + + player2-slots: + - 5 + - 6 + - 7 + - 8 + - 14 + - 15 + - 16 + - 17 + - 23 + - 24 + - 25 + - 26 + - 32 + - 33 + - 34 + - 35 + - 41 + - 42 + - 43 + - 44 + - 50 + - 51 + - 52 + - 53 + + accept-slot: 22 + decline-slot: 31 + +items: + divider: + material: BLACK_STAINED_GLASS_PANE + name: "&0" + lore: [] + + accept: + material: LIME_CONCRETE + name: "&aAccept Trade" + lore: + - "&7Click to accept." + - "&7If items change, accept resets." + + accepted: + material: GREEN_CONCRETE + name: "&aAccepted" + lore: + - "&7Waiting for the other player..." + + decline: + material: RED_CONCRETE + name: "&cDecline Trade" + lore: + - "&7Click to cancel this trade." + +messages: + prefix: "&6[DirtTrades] &r" + + no-permission: "&cYou do not have permission." + player-only: "&cOnly players can use this command." + usage: "&eUsage: /trade " + player-not-found: "&cThat player is not online." + cannot-trade-self: "&cYou cannot trade with yourself." + target-no-permission: "&cThat player cannot use trades." + already-in-trade: "&cYou or that player is already in a trade." + request-sent: "&aTrade request sent to &e%target%&a." + request-received: "&e%sender% &ahas sent you a trade request." + request-received-hover: "&7Use &f/trade accept &7or &f/trade deny" + no-pending-request: "&cYou have no pending trade request." + request-accepted: "&aYou accepted the trade request from &e%sender%&a." + request-denied: "&cYou denied the trade request from &e%sender%&c." + request-denied-sender: "&c%target% denied your trade request." + request-expired-sender: "&cYour trade request to &e%target% &cexpired." + request-expired-target: "&cThe trade request from &e%sender% &cexpired." + trade-started: "&aTrade started with &e%player%&a." + trade-cancelled: "&cTrade cancelled." + trade-cancelled-other: "&cThe trade was cancelled by the other player." + trade-completed: "&aTrade completed successfully." + inventory-full-drop: "&eYour inventory was full, so some items were dropped." + config-reloaded: "&aDirtTrades config reloaded." + creative-blocked: "&cYou cannot trade while in creative mode." + too-far: "&cTrade cancelled because a player moved too far away." + + actionbar-waiting-self: "&aYou accepted &7- waiting for the other player..." + actionbar-waiting-other: "&eOther player accepted &7- click accept to finish." + actionbar-cleared: "" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..5ce9578 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,25 @@ +name: DirtTrades +version: 1.0-SNAPSHOT +main: com.yourname.dirttrades.DirtTradesPlugin +api-version: '1.21' + +commands: + trade: + description: Main trade command + usage: /trade + aliases: [dtrade, trades] + +permissions: + dirttrades.use: + description: Allows using trade commands + default: true + + dirttrades.reload: + description: Allows reloading the plugin config + default: op + + dirttrades.admin: + description: Admin access to DirtTrades + default: op + children: + dirttrades.reload: true diff --git a/target/DirtTrades-1.0-SNAPSHOT.jar b/target/DirtTrades-1.0-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..3475474f2728d9aa3d8b1e36759cd45289b154cd GIT binary patch literal 23041 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 E?z{1L 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/DirtTradesPlugin.class b/target/classes/com/yourname/dirttrades/DirtTradesPlugin.class new file mode 100644 index 0000000000000000000000000000000000000000..8976bffeb0cc616f1d4880248af5d4d60098598b GIT binary patch literal 2046 zcmb7FYjfK~6g^ufk)v#r*lAKj6OuM*V>>izDU^cCqs;>-N(psv3D4Qs8&yP>GO`@t z-|!P)23(*seB=W^is9}`cI1vtU_7(h$K7+!J@@YQUw{Ap2Y`F{+Qd0z42*D$VvON( z5IWXD`{>AxtYfe3xW4s`I1$zZ8g})XVeGE!yV2VWnPRDCB8zbYCdY)jU#tgB>-(S` z`l2bVh8spvC>pY5ZPIj4PrER=mN=1{@=&zBXe00sUB|$AhLvFm`u2|Sg(E`~98-$& zG{g0xJ?zT!PAjF_IPuMM%-{k8*W40FhHFD{(yl88=FVcd5j2~^Z4GSDEVUfXfBnhe+Fx)QMI)R?>9jh9JuJ2Szb}GxHo#JZ6X-V!? zOkBnl1IrvMxXQ3})&+)%mW;N(ll68Kgbb_2K|T`nt{J66`B~*CqQo#o2z%myjE+4S zNkUl}h?2I^5NmkZz;%vwSPZ!o)%&`T8Ky~*IKE!8my3NW9LKfZXGEF4$#9hf8d%Y~ zC~UVCNnaJ@4HPEuDqb^io8xudVOUHt8HCR;8A?Y1gj*-lk6H|O`T~|}*Xp{cq!sPM z(;{T?CPxK#8OAAEJ8EesQ|3_w2}oq;+fM&vLtbxJ6%feKL${4Fg=w^JnLduFFd>jSAQ1hf@ z{cE)))l0yMJ~3B%@>OcNb-C>-0cM|%WnJZu9$J=qJ-}$B_D8c(np4-OahFyWeVN)V zKLz`VCg<=mjp|s9k7(qv0jk)e6~iaJ%Rdm10^conV3ePM?-R=8FUUQ^?0&iYGjdOH z(Jtp->|lPagQec=+OHt<8(o`M%D>@O288lP{;dw)IpuMM=qm;zn8Y;w7Lda#^0-N% zY-5h9Ch+;THoF4SC+)`XtoJmGz*S$y>mGDi$t literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/TradeCommand.class b/target/classes/com/yourname/dirttrades/TradeCommand.class new file mode 100644 index 0000000000000000000000000000000000000000..0076892aaf1675ced3ed6b76de94c4014c4ac6c7 GIT binary patch literal 3966 zcmc&%TW}NS75;u%(n|8$*zyHLpj<-0vav-;8-heG#z27B24ZT!q)FD&T3(QLmE9G= zz0qqfO)qJZHX&)+^qO8so3z2fWrk@Ul9_gF?OUhMed$9d!=(NG-4&8-O!Cye z?EZUn_FTU6owG;3fA2R}01V?-353w1Agm&Ss6fXl?TnTwX=X8VX!?|%cLk!m4AXG$ z6lm#7PsR~LTtPxbD^!6^d8?e6v#PeKmGw-)uwB>I3c8ayDsLlJxvZH5ny8ejMZ*;6 zA6@Q+J$%=D$vN!l=A@@~6)Vsopn6uvG*c_;w!r3Pt#}p!y_|xiz$(iwW~QsBPaAGV zH(kS>%N#CgbGjWvHv_ZvlBE?A=*3C}t5l@0x(S2{*EY-|Mf$^4t>hdinwG7PXpSz> z(>GcN%h$`Lr(#$m&{;=f$oJ5S4`H2x^(r<<59=GEA|eu{On}yeZWd&cZL^wlShvfD z;~171!_5q$!K_v&8`1u#mvL7*#N)VjPD^jRs@8Jz6r{ zqVD>n+H6#ArLd1LuSb^Sq=6p>G(17CcwwE+`$>EYLf3; za7@KJZDl|+p z>AId&VYpg>qoS#+{1L>ik{}jT=$K)^M9WXn$IM}q_oaQBdTvLoQi+p`U6X6YEDQyw zRGdahpu6s~t|T#Ybz5^Sc3p3ir2~PSc1&0bDk>h9ASdf~YAON>8+Kej>q=cmg^Mbg zVNyW9HLDGSl{P!^h>EkAmk=uCv;)QvKe7lz&H;;Sr2ksT6kQ=6Zo<~ zTrXE#ua?ZdmQ7t*!B+$}HV|~tP}_S}&sPbsg0BgzyN=#bZJP71QqqaIz(n7&6Mo5e zVp+|mZ$WyJsg76$BD`Xh-7#J*PwO_lmMBS%T6wKBso92n4uoNM)*wFb^Q{Snc8&;H zX7C^|)6_tVu=X1=_&8SD!*j{s~gQVPX}tr7MEHZ8?_cW4Zjg4Syc9HOPT_Mx@h?1-1JxA_@tL0CRX_Wx_Hp^__ zgFy9v0%yYn@fv^uS`|4(2#J4SJ{?Q7B8FM1G7F`wx%pY0N)fGOXuS6}^J=bAmo38QFgZq+77pZI@ZuuNQu32uCOeV-wlr_<}R5r2spl2e8&PK;Y+2v6dx zye8$U$YnDrcRAi$K!oshUZ3LA3AumrzM}t4i2i|#Q2MuCMBD2Wh42ktlL+(L#cMa> z=s`Qj-P4q;_g}*^c$QBz;JFdrNjeJA!8h?O-%aQ#YR3Rk9C!jsh=gJbtV{~KsaZkosD1#Ar=e1Xr(Jhu7r zkJjbBU`Jh$iX?X~ASVrO;F%V^b5APLU~-o<$zWbUO@4=GA&|Fh&qhlr?Hve)h%$ivp$IdyojxM z2^stV+wf~Hj~BT(UdC;B8$0kv+>SpXhreJK{*F8F58RD^Vpu5HEmmSgq_~i+$30>j z_KWSfSM0>7*pD%B9OGgNM}*EbNz&(jlBta`K8NSYMiQe&B%aPQK@y3l7x8TpNuFN9 zcO>C>`Yv8386Es9c=s|c;CuWvN?$|xKJ6)t9L!Vg*tzm5IuvxKd0(xdxBJ#rSJ6X3 zCms9{KcaCqf%qHm3BK|NpN(%{#?*;7aep?#^4+z7kB4xKr@j8EPS5rlJsr=s)tjP$Ie;x$u$PAQl0xs>wSB|P>T6AF7AILIajjuDsR`2W1vTa=s4-7J_iN0PUt`JQUY5qU`zr1F x)?N)Nd<$Y%kyY?O{Hpv@Y`%*v?|EgWh>u&}Md;sD{RPd0@Jm))LK4F3{{ literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/TradeListener$1.class b/target/classes/com/yourname/dirttrades/TradeListener$1.class new file mode 100644 index 0000000000000000000000000000000000000000..bde2f497bbe4335bf1e5622edfc06e2083d80d9e GIT binary patch literal 762 zcmb7CU279T6g`uy*(7dltkr(_(OS3Kin#dTlOmLo(qOU+O^8Sz!en?G1( z7RK`)24%&btt_)i#~`rWtE#^Vluv2|3_)*xK*QzUh%Mq z2E$4x>Nf|yXb|-dn@59I*l&it=;$@WqyM=^-n%6a*RagsYLiICQ-<=+Zp+0DhV>IZ z=RwNVC{ur* z?lEj%Xda|C6q!BL8434Vibk}b@+=csW0U5)Lhp+;R`Utx7BOpBC%j2sh%#Bg+Gnt{ zul0{`Kjh!SCtP)+cW_?5r|lY+smOH-y+xswB4L2rWS3~&q2;3V%B2W6*eK{t+$D6d SMSs6wwy;fDr{pRj8r2_+AjU8N literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/TradeListener.class b/target/classes/com/yourname/dirttrades/TradeListener.class new file mode 100644 index 0000000000000000000000000000000000000000..e2dec2171de48d5d33f5053744336d0f0e9818e1 GIT binary patch literal 7544 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 Dzg02Z literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/TradeManager$TradeRequest.class b/target/classes/com/yourname/dirttrades/TradeManager$TradeRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..cf52302217e96e404157b30f9b54d1179a29e1ab GIT binary patch literal 652 zcmb7C%Wf1g5Uk#v>|+?R$?_&Vg2*9R5EkMXgako|NJEfdvr>-UnbyYH*%`1s2tI?y zk8p^PIPd{{6rw$Fh;o99tE=U%vdjMY>-!G?k8v|b3+*nV1WV`;R*v*LtqNVv)XV7+ zXP(e`XiDQB5!#zulRkRrcM&HzgM@HDs}|}*RohZ8SmnlgZ*|U2jRU;UrJk|fXviym zTeAy#j?0{_c%_Y5?Myl(k9=MHRcqplcAy&Z_R^DwHY`s>kyI5 zd_+W_(5KH>rZ2c4{q;X%xQI)_M4+*wrV55Z_Oh@RuHb5eYq%~Li*XNYxPkaLij12b literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/TradeManager.class b/target/classes/com/yourname/dirttrades/TradeManager.class new file mode 100644 index 0000000000000000000000000000000000000000..9a47c6b5669a94156165b56ccba3d8a1b2451751 GIT binary patch literal 14908 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/yourname/dirttrades/TradeSession.class b/target/classes/com/yourname/dirttrades/TradeSession.class new file mode 100644 index 0000000000000000000000000000000000000000..08c9b5197c2eef132145a4e343164ef0dfc9952c GIT binary patch literal 9811 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 literal 0 HcmV?d00001 diff --git a/target/classes/config.yml b/target/classes/config.yml new file mode 100644 index 0000000..85a8b60 --- /dev/null +++ b/target/classes/config.yml @@ -0,0 +1,131 @@ +settings: + request-expire-seconds: 30 + prevent-self-trade: true + block-creative-mode-trading: true + close-on-move-out-of-range: false + max-trade-distance: 10.0 + drop-items-if-inventory-full: true + sound-enabled: true + actionbar-enabled: true + +gui: + title: "&8Dirt Trade: %player1% &7<-> &f%player2%" + size: 54 + + divider-slots: + - 4 + - 13 + - 40 + - 49 + + player1-slots: + - 0 + - 1 + - 2 + - 3 + - 9 + - 10 + - 11 + - 12 + - 18 + - 19 + - 20 + - 21 + - 27 + - 28 + - 29 + - 30 + - 36 + - 37 + - 38 + - 39 + - 45 + - 46 + - 47 + - 48 + + player2-slots: + - 5 + - 6 + - 7 + - 8 + - 14 + - 15 + - 16 + - 17 + - 23 + - 24 + - 25 + - 26 + - 32 + - 33 + - 34 + - 35 + - 41 + - 42 + - 43 + - 44 + - 50 + - 51 + - 52 + - 53 + + accept-slot: 22 + decline-slot: 31 + +items: + divider: + material: BLACK_STAINED_GLASS_PANE + name: "&0" + lore: [] + + accept: + material: LIME_CONCRETE + name: "&aAccept Trade" + lore: + - "&7Click to accept." + - "&7If items change, accept resets." + + accepted: + material: GREEN_CONCRETE + name: "&aAccepted" + lore: + - "&7Waiting for the other player..." + + decline: + material: RED_CONCRETE + name: "&cDecline Trade" + lore: + - "&7Click to cancel this trade." + +messages: + prefix: "&6[DirtTrades] &r" + + no-permission: "&cYou do not have permission." + player-only: "&cOnly players can use this command." + usage: "&eUsage: /trade " + player-not-found: "&cThat player is not online." + cannot-trade-self: "&cYou cannot trade with yourself." + target-no-permission: "&cThat player cannot use trades." + already-in-trade: "&cYou or that player is already in a trade." + request-sent: "&aTrade request sent to &e%target%&a." + request-received: "&e%sender% &ahas sent you a trade request." + request-received-hover: "&7Use &f/trade accept &7or &f/trade deny" + no-pending-request: "&cYou have no pending trade request." + request-accepted: "&aYou accepted the trade request from &e%sender%&a." + request-denied: "&cYou denied the trade request from &e%sender%&c." + request-denied-sender: "&c%target% denied your trade request." + request-expired-sender: "&cYour trade request to &e%target% &cexpired." + request-expired-target: "&cThe trade request from &e%sender% &cexpired." + trade-started: "&aTrade started with &e%player%&a." + trade-cancelled: "&cTrade cancelled." + trade-cancelled-other: "&cThe trade was cancelled by the other player." + trade-completed: "&aTrade completed successfully." + inventory-full-drop: "&eYour inventory was full, so some items were dropped." + config-reloaded: "&aDirtTrades config reloaded." + creative-blocked: "&cYou cannot trade while in creative mode." + too-far: "&cTrade cancelled because a player moved too far away." + + actionbar-waiting-self: "&aYou accepted &7- waiting for the other player..." + actionbar-waiting-other: "&eOther player accepted &7- click accept to finish." + actionbar-cleared: "" diff --git a/target/classes/plugin.yml b/target/classes/plugin.yml new file mode 100644 index 0000000..5ce9578 --- /dev/null +++ b/target/classes/plugin.yml @@ -0,0 +1,25 @@ +name: DirtTrades +version: 1.0-SNAPSHOT +main: com.yourname.dirttrades.DirtTradesPlugin +api-version: '1.21' + +commands: + trade: + description: Main trade command + usage: /trade + aliases: [dtrade, trades] + +permissions: + dirttrades.use: + description: Allows using trade commands + default: true + + dirttrades.reload: + description: Allows reloading the plugin config + default: op + + dirttrades.admin: + description: Admin access to DirtTrades + default: op + children: + dirttrades.reload: true diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties new file mode 100644 index 0000000..f5df43e --- /dev/null +++ b/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Sun Jun 14 15:02:31 EDT 2026 +artifactId=DirtTrades +groupId=com.yourname +version=1.0-SNAPSHOT diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..4848ac4 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,7 @@ +com/yourname/dirttrades/TradeListener$1.class +com/yourname/dirttrades/TradeCommand.class +com/yourname/dirttrades/TradeListener.class +com/yourname/dirttrades/DirtTradesPlugin.class +com/yourname/dirttrades/TradeManager$TradeRequest.class +com/yourname/dirttrades/TradeManager.class +com/yourname/dirttrades/TradeSession.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..bbbf191 --- /dev/null +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,5 @@ +/home/bitnix/Desktop/DirtTrades/src/main/java/com/yourname/dirttrades/DirtTradesPlugin.java +/home/bitnix/Desktop/DirtTrades/src/main/java/com/yourname/dirttrades/TradeCommand.java +/home/bitnix/Desktop/DirtTrades/src/main/java/com/yourname/dirttrades/TradeListener.java +/home/bitnix/Desktop/DirtTrades/src/main/java/com/yourname/dirttrades/TradeManager.java +/home/bitnix/Desktop/DirtTrades/src/main/java/com/yourname/dirttrades/TradeSession.java