This commit is contained in:
yaohunya 2025-08-12 01:14:12 +08:00
commit d4b0aa1e4b
19 changed files with 1302 additions and 0 deletions

37
pom.xml Normal file
View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>DemonTrade</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>public-rpg</id>
<url>https://repo.aurora-pixels.com/repository/public-rpg/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12.2</version>
</dependency>
<dependency>
<groupId>me.Demon.DemonPlugin</groupId>
<artifactId>DemonAPI</artifactId>
<version>2.2.9</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,96 @@
package com.yaohun.trade;
import com.yaohun.trade.config.Config;
import com.yaohun.trade.data.TradeData;
import com.yaohun.trade.gui.GuiMain;
import com.yaohun.trade.listener.BreakBlcok;
import com.yaohun.trade.listener.ClickInventory;
import com.yaohun.trade.listener.PlayerListener;
import com.yaohun.trade.manage.InviteManager;
import com.yaohun.trade.manage.LogsManager;
import com.yaohun.trade.util.MessageUtil;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public class TradeMain extends JavaPlugin {
private static TradeMain instance;
private static LogsManager logsManager;
@Override
public void onEnable() {
instance = this;
Config.reloadConfig(this);
logsManager = new LogsManager();
getServer().getPluginManager().registerEvents(new GuiMain(), this);
getServer().getPluginManager().registerEvents(new BreakBlcok(), this);
getServer().getPluginManager().registerEvents(new ClickInventory(), this);
getServer().getPluginManager().registerEvents(new PlayerListener(), this);
}
@Override
public void onDisable() {
getLogsManager().saveAllLog();
for (TradeData tradeData : InviteManager.tradeData){
tradeData.closeTradeGui(true);
}
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if(args.length == 0){
String message = Config.getString("commandUsageInvite");
MessageUtil.sendMessage(sender, message, Sound.ENTITY_VILLAGER_NO);
return true;
}
if(args.length == 1) {
if ("reload".equalsIgnoreCase(args[0]) && sender.isOp()) {
Config.reloadConfig(this);
sender.sendMessage("[交易] 配置文件已重载.");
return true;
}
if ("save".equalsIgnoreCase(args[0]) && sender.isOp()) {
getLogsManager().saveAllLog();
sender.sendMessage("[交易] 正在保存日志数据.");
return true;
}
if ("list".equalsIgnoreCase(args[0]) && sender.isOp()) {
sender.sendMessage("[交易] 正在进行的交易:");
for (TradeData tradeData : InviteManager.tradeData){
sender.sendMessage(" - "+tradeData.getTradeID()+" "+tradeData.getPlayerName()+" <-> "+tradeData.getTargetName());
}
return true;
}
if ("accept".equalsIgnoreCase(args[0])) {
InviteManager.acceptInvite((Player) sender);
return true;
}
if ("deny".equalsIgnoreCase(args[0])) {
InviteManager.denyInvite((Player) sender);
return true;
}
Player player = (Player) sender;
String tragetName = args[0];
Player target = Bukkit.getPlayer(tragetName);
if(target == null || !target.isOnline()){
String message = Config.getString("invitePlayerOffline");
MessageUtil.sendMessage(player, message, Sound.ENTITY_VILLAGER_NO);
return true;
}
InviteManager.sendInvite(player, target);
}
return false;
}
public static TradeMain inst() {
return instance;
}
public static LogsManager getLogsManager() {
return logsManager;
}
}

View File

@ -0,0 +1,48 @@
package com.yaohun.trade.config;
import com.yaohun.trade.TradeMain;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.data.LangData;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.util.List;
public class Config {
public static String invTitle = "玩家交易系统";
private static LangData langData;
private static boolean breakChestEnabled;
private static List<String> breakChestWorlds;
private static int limitDistance;
public static int[] playerButts = new int[]{36,37,38,39};
public static int[] targetButts = new int[]{41,42,43,44};
public static int[] playerSlots = new int[]{0,1,2,3,9,10,11,12,18,19,20,21,27,28,29,30};
public static int[] targetSlots = new int[]{5,6,7,8,14,15,16,17,23,24,25,26,32,33,34,35};
public static void reloadConfig(TradeMain plugin){
langData = DemonAPI.getLangData("DemonTrade");
plugin.reloadConfig();
plugin.saveConfig();
FileConfiguration config = plugin.getConfig();
breakChestEnabled = config.getBoolean("BreakChest.enabled");
breakChestWorlds = config.getStringList("BreakChest.worlds");
limitDistance = config.getInt("LimitDistance",32);
}
public static String getString(String key){
return langData.getMessage(key);
}
public static int getLimitDistance() {
return limitDistance;
}
public static boolean isBreakChestEnabled(){
return breakChestEnabled;
}
public static boolean isBreakChestWorld(String world){
return breakChestWorlds.contains(world);
}
}

View File

@ -0,0 +1,36 @@
package com.yaohun.trade.data;
import org.bukkit.entity.Player;
public class InviteData {
private Player player;
private Player target;
private long initiationTime;
public InviteData(Player player, Player target) {
this.player = player;
this.target = target;
this.initiationTime = System.currentTimeMillis();
}
public Player getPlayer() {
return player;
}
public String playerName(){
return player.getName();
}
public Player getTarget() {
return target;
}
public String targetName(){
return target.getName();
}
public boolean isExpired() {
return System.currentTimeMillis() - initiationTime > 1000 * 30;
}
}

View File

@ -0,0 +1,221 @@
package com.yaohun.trade.data;
import com.yaohun.trade.TradeMain;
import com.yaohun.trade.util.StackUtil;
import com.yaohun.trade.config.Config;
import com.yaohun.trade.util.MessageUtil;
import com.yaohun.trade.util.TradeState;
import me.Demon.DemonPlugin.DemonAPI;
import org.bukkit.ChatColor;
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.HashMap;
import java.util.List;
public class TradeData {
private final String tradeID = "DATA-"+System.currentTimeMillis();
private Player player;
private String playerName;
private Player target;
private String targetName;
private boolean isTradeStop;
private boolean isTradeBreakTheLaw;
private HashMap<Player, TradeState> stateMap = new HashMap<>();
private Inventory inventory;
public TradeData(Player player, Player target,Inventory inventory) {
this.player = player;
this.playerName = player.getName();
stateMap.put(player, TradeState.OPEN);
this.target = target;
this.targetName = target.getName();
stateMap.put(target, TradeState.OPEN);
this.inventory = inventory;
this.isTradeStop = false;
this.isTradeBreakTheLaw = false;
}
public String getTradeID() {
return tradeID;
}
public void setTradeBreakTheLaw(boolean tradeBreakTheLaw) {
isTradeBreakTheLaw = tradeBreakTheLaw;
}
public boolean isTradeStop() {
return isTradeStop;
}
public Player getPlayer() {
return player;
}
public String getPlayerName() {
return playerName;
}
public Player getTarget() {
return target;
}
public String getTargetName() {
return targetName;
}
public TradeState getState(Player player){
return stateMap.get(player);
}
public void setStateData(Player player, TradeState state){
stateMap.put(player, state);
}
public boolean isMutualComfirm(){
return stateMap.get(player) == TradeState.CONFIRM && stateMap.get(target) == TradeState.CONFIRM;
}
private boolean isInventoryFull(boolean targetD){
if(targetD){
int slotAmount = 0;
for (int slot : Config.playerButts.clone()) {
ItemStack stack = inventory.getItem(slot);
if (!DemonAPI.itemIsNull(stack)) {
slotAmount++;
}
}
if (!DemonAPI.hasEmptyInventorySlots(target, slotAmount)) {
return false;
}
} else {
int slotAmount = 0;
for (int slot : Config.targetSlots.clone()) {
ItemStack stack = inventory.getItem(slot);
if (!DemonAPI.itemIsNull(stack)) {
slotAmount++;
}
}
if (!DemonAPI.hasEmptyInventorySlots(player, slotAmount)) {
return false;
}
}
return true;
}
public void successTrade(){
if(!isInventoryFull(false)){
isTradeBreakTheLaw = true;
player.closeInventory();
MessageUtil.sendMessage(player,Config.getString("insufficientSpace"), Sound.ENTITY_BLAZE_DEATH);
MessageUtil.sendMessage(target,Config.getString("insufficientSpace"), Sound.ENTITY_BLAZE_DEATH);
return;
}
if(!isInventoryFull(true)){
isTradeBreakTheLaw = true;
target.closeInventory();
MessageUtil.sendMessage(player,Config.getString("insufficientSpace2"), Sound.ENTITY_BLAZE_DEATH);
MessageUtil.sendMessage(target,Config.getString("insufficientSpace2"), Sound.ENTITY_BLAZE_DEATH);
return;
}
this.isTradeStop = true;
int playerCount = 0;
List<String> playerList = new ArrayList<>();
for (int slot : Config.targetSlots.clone()){
ItemStack stack = inventory.getItem(slot);
if(!DemonAPI.itemIsNull(stack)){
if(stack.getType().equals(Material.STAINED_GLASS_PANE)){
continue;
}
ItemStack item = StackUtil.removeTagStack(stack);
int amount = stack.getAmount();
String itemName = DemonAPI.getItemName(item);
playerList.add(ChatColor.stripColor(itemName)+"x"+amount);
DemonAPI.giveItem(player, item);
playerCount += amount;
}
}
player.closeInventory();
int tragetCount = 0;
List<String> targetList = new ArrayList<>();
for (int slot : Config.playerSlots.clone()){
ItemStack stack = inventory.getItem(slot);
if(!DemonAPI.itemIsNull(stack)){
if(stack.getType().equals(Material.STAINED_GLASS_PANE)){
continue;
}
ItemStack item = StackUtil.removeTagStack(stack);
int amount = stack.getAmount();
String itemName = DemonAPI.getItemName(item);
targetList.add(ChatColor.stripColor(itemName)+"x"+amount);
DemonAPI.giveItem(target, item);
tragetCount += stack.getAmount();
}
}
target.closeInventory();
String CompleteTrade = Config.getString("CompleteTrade");
String CompleteTrade2 = Config.getString("CompleteTrade2");
if(playerCount >= 1) {
MessageUtil.sendMessage(player, CompleteTrade.replace("{count}", String.valueOf(playerCount)), Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
} else {
MessageUtil.sendMessage(player, CompleteTrade2, Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
}
if(tragetCount >= 1) {
MessageUtil.sendMessage(target, CompleteTrade.replace("{count}", String.valueOf(tragetCount)), Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
} else {
MessageUtil.sendMessage(target, CompleteTrade2, Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
}
TradeLogData logData = new TradeLogData();
logData.setTradeID(getTradeID());
logData.setPlayerName(player.getName());
logData.setTargetName(target.getName());
logData.setTradeTime(System.currentTimeMillis());
logData.setPlayerList(playerList);
logData.setTargetList(targetList);
TradeMain.getLogsManager().addLogData(logData);
}
public void closeTradeGui(boolean closePlayer){
this.isTradeStop = true;
for (int slot : Config.playerSlots.clone()){
ItemStack stack = inventory.getItem(slot);
if(!DemonAPI.itemIsNull(stack)){
if(stack.getType().equals(Material.STAINED_GLASS_PANE)){
continue;
}
ItemStack item = StackUtil.removeTagStack(stack);
DemonAPI.giveItem(player, item);
}
}
player.closeInventory();
for (int slot : Config.targetSlots.clone()){
ItemStack stack = inventory.getItem(slot);
if(!DemonAPI.itemIsNull(stack)){
if(stack.getType().equals(Material.STAINED_GLASS_PANE)){
continue;
}
ItemStack item = StackUtil.removeTagStack(stack);
DemonAPI.giveItem(target, item);
}
}
target.closeInventory();
if(!isTradeBreakTheLaw) {
String message = Config.getString("closeTheInterface");
String message2 = Config.getString("closeTheInterface2");
if (closePlayer) {
MessageUtil.sendMessage(player, message.replace("{name}",targetName), Sound.ENTITY_VILLAGER_NO);
MessageUtil.sendMessage(target, message2.replace("{name}",playerName), Sound.ENTITY_VILLAGER_NO);
} else {
MessageUtil.sendMessage(target, message.replace("{name}",playerName), Sound.ENTITY_VILLAGER_NO);
MessageUtil.sendMessage(player, message2.replace("{name}",targetName), Sound.ENTITY_VILLAGER_NO);
}
}
}
}

View File

@ -0,0 +1,73 @@
package com.yaohun.trade.data;
import java.util.List;
public class TradeLogData {
private String tradeID;
private String playerName;
private String targetName;
private long tradeTime;
private List<String> playerList;
private List<String> targetList;
public TradeLogData(String tradeID, String playerName, String targetName, long tradeTime, List<String> playerList, List<String> targetList) {
this.tradeID = tradeID;
this.playerName = playerName;
this.targetName = targetName;
this.tradeTime = tradeTime;
this.playerList = playerList;
this.targetList = targetList;
}
public TradeLogData() {
}
public void setTradeID(String tradeID) {
this.tradeID = tradeID;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
public void setTargetName(String targetName) {
this.targetName = targetName;
}
public void setTradeTime(long tradeTime) {
this.tradeTime = tradeTime;
}
public void setPlayerList(List<String> playerList) {
this.playerList = playerList;
}
public void setTargetList(List<String> targetList) {
this.targetList = targetList;
}
public String getTradeID() {
return tradeID;
}
public String getPlayerName() {
return playerName;
}
public String getTargetName() {
return targetName;
}
public long getTradeTime() {
return tradeTime;
}
public List<String> getPlayerList() {
return playerList;
}
public List<String> getTargetList() {
return targetList;
}
}

View File

@ -0,0 +1,70 @@
package com.yaohun.trade.gui;
import com.yaohun.trade.manage.InviteManager;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.data.NbtItem;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class GuiMain implements Listener {
@EventHandler
public void onclick(InventoryClickEvent e){
Player p = (Player) e.getWhoClicked();
Inventory inv = e.getInventory();
int rawSlot = e.getRawSlot();
if(inv != null && inv.getTitle().contains("向你发起的交易请求?")){
e.setCancelled(true);
if(rawSlot >= 0 && rawSlot < 27) {
ItemStack item = e.getCurrentItem();
if (!DemonAPI.itemIsNull(item)) {
NbtItem nbti = new NbtItem(item);
if(nbti.hasKey("trade_yes")){
p.closeInventory();
InviteManager.acceptInvite(p);
p.playSound(p.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1);
}
if(nbti.hasKey("trade_no")){
p.closeInventory();
InviteManager.denyInvite(p);
p.playSound(p.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1);
}
}
}
}
}
public static void OpenGui(Player p,String playName){
Inventory inv = Bukkit.createInventory(null,27,"是否接受"+playName+"向你发起的交易请求?");
for (int i : new int[]{0,1,2,3,9,10,11,12,18,19,20,21}){
inv.setItem(i, YesTrade(playName));
}
for (int i : new int[]{5,6,7,8,14,15,16,17,23,24,25,26}){
inv.setItem(i, NoTrade(playName));
}
p.openInventory(inv);
}
public static ItemStack YesTrade(String playName){
ItemStack item = DemonAPI.glass(5,"§a§l同意请求");
NbtItem nbti = new NbtItem(item);
nbti.setString("trade_yes",playName);
item = nbti.getItem();
return item;
}
public static ItemStack NoTrade(String playName){
ItemStack item = DemonAPI.glass(14,"§c§l拒绝请求");
NbtItem nbti = new NbtItem(item);
nbti.setString("trade_no",playName);
item = nbti.getItem();
return item;
}
}

View File

@ -0,0 +1,85 @@
package com.yaohun.trade.gui;
import com.yaohun.trade.config.Config;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.data.NbtItem;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.*;
public class TradeGui implements InventoryHolder {
private Inventory inventory;
private Player player;
private Player target;
private int[] progressSlot = new int[]{4,13,22,31,40};
public TradeGui(Player player, Player target) {
this.player = player;
this.target = target;
this.inventory = Bukkit.createInventory(null,45,Config.invTitle);
initPlayerGlass();
initTargetGlass();
ItemStack stack = DemonAPI.glass(3,"§a§l▷▷▷§7[§c"+target.getName()+"§7]§a§l▷▷▷");
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("§b§l◀◀◀§7[§a"+player.getName()+"§7]§b§l◀◀◀");
meta.setLore(lore);
stack.setItemMeta(meta);
for (int slot : progressSlot){
this.inventory.setItem(slot,stack);
}
}
private void initPlayerGlass(){
ItemStack stack = DemonAPI.glass(6,"§a确认按钮");
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("§l"+player.getName());
meta.setLore(lore);
stack.setItemMeta(meta);
NbtItem nbtItem = new NbtItem(stack);
nbtItem.setString("buttOwner",player.getName());
for(int i = 0; i < Config.playerButts.length; i++){
inventory.setItem(Config.playerButts[i],nbtItem.getItem());
}
ItemStack equipSlot = DemonAPI.glass(8,"§7[§c空§7]");
for (int i : Config.playerSlots){
inventory.setItem(i,equipSlot);
}
}
private void initTargetGlass(){
ItemStack stack = DemonAPI.glass(4,"§a确认按钮");
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("§l"+target.getName());
meta.setLore(lore);
stack.setItemMeta(meta);
NbtItem nbtItem = new NbtItem(stack);
nbtItem.setString("buttOwner",target.getName());
for(int i = 0; i < Config.targetButts.length; i++){
inventory.setItem(Config.targetButts[i],nbtItem.getItem());
}
ItemStack equipSlot = DemonAPI.glass(8,"§7[§c空§7]");
for (int i : Config.targetSlots){
inventory.setItem(i,equipSlot);
}
}
@Override
public Inventory getInventory() {
return inventory;
}
}

View File

@ -0,0 +1,52 @@
package com.yaohun.trade.listener;
import com.yaohun.trade.config.Config;
import com.yaohun.trade.util.MessageUtil;
import me.Demon.DemonPlugin.DemonAPI;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.entity.Player;
import org.bukkit.entity.Wolf;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class BreakBlcok implements Listener {
@EventHandler
public void onBreak(BlockBreakEvent e) {
Player player = e.getPlayer();
World world = player.getWorld();
if (Config.isBreakChestEnabled()) {
if (Config.isBreakChestWorld(world.getName())) {
if (!player.isOp()) {
return;
}
Block block = e.getBlock();
BlockState blockState = block.getState();
if (blockState instanceof Chest) {
Chest chest = (Chest) blockState;
Inventory inv = chest.getBlockInventory();
boolean stats = false;
for (int slot = 0; slot < inv.getSize(); slot++) {
ItemStack stack = inv.getItem(slot);
if (DemonAPI.itemIsNull(stack) || DemonAPI.itemIsLore(stack)) {
continue;
}
stats = true;
break;
}
if (stats) {
e.setCancelled(true);
MessageUtil.sendMessage(player, Config.getString("breakchest"), Sound.ENTITY_VILLAGER_NO);
}
}
}
}
}
}

View File

@ -0,0 +1,205 @@
package com.yaohun.trade.listener;
import com.yaohun.trade.util.StackUtil;
import com.yaohun.trade.config.Config;
import com.yaohun.trade.data.TradeData;
import com.yaohun.trade.manage.InviteManager;
import com.yaohun.trade.util.MessageUtil;
import com.yaohun.trade.util.TradeState;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.Util.CDTimeAPI;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ClickInventory implements Listener {
@EventHandler
public void onClick(InventoryClickEvent e){
int rawSlot = e.getRawSlot();
Player player = (Player) e.getWhoClicked();
UUID uuid = player.getUniqueId();
Inventory inv = e.getInventory();
if(e.getView().getTitle().equalsIgnoreCase(Config.invTitle)){
if(e.getClick() == ClickType.DOUBLE_CLICK){
e.setCancelled(true);
player.closeInventory();
MessageUtil.sendMessage(player,Config.getString("doubleClickAnit"),Sound.ENTITY_VILLAGER_NO);
return;
}
if(e.getClick() == ClickType.SHIFT_LEFT || e.getClick() == ClickType.SHIFT_RIGHT){
e.setCancelled(true);
player.closeInventory();
MessageUtil.sendMessage(player,Config.getString("shfitClickAnit"),Sound.ENTITY_VILLAGER_NO);
return;
}
if(rawSlot >0 && rawSlot < 45) {
e.setCancelled(true);
TradeData tradeData = InviteManager.getTradeData(player);
if(tradeData == null){
player.closeInventory();
return;
}
ItemStack stack = e.getCurrentItem();
if(tradeData.getPlayer().equals(player)){
if(!isClickValidPlace(false,rawSlot)){
if(rawSlot == 36 || rawSlot == 37 || rawSlot == 38 || rawSlot == 39){
if(tradeData.getState(player).equals(TradeState.CONFIRM)){
return;
}
tradeData.setStateData(player,TradeState.CONFIRM);
if(tradeData.isMutualComfirm()){
// 执行交易操作
tradeData.successTrade();
InviteManager.tradeData.remove(tradeData);
} else {
confirmGlassState(inv, false);
MessageUtil.sendMessage(player,Config.getString("ConfirmTheTrade"), Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
MessageUtil.sendMessage(tradeData.getTarget(), Config.getString("ConfirmTheTrade2"), Sound.ENTITY_CAT_AMBIENT);
}
return;
}
if(CDTimeAPI.isCD(uuid,"crossingClick")) {
tradeData.setTradeBreakTheLaw(true);
MessageUtil.sendMessage(player, Config.getString("crossingTheLine"), Sound.ENTITY_BLAZE_DEATH);
MessageUtil.sendMessage(tradeData.getTarget(), Config.getString("crossingTheLine2").replace("{name}", player.getName()), Sound.ENTITY_BLAZE_DEATH);
player.closeInventory();
} else {
MessageUtil.sendMessage(player, Config.getString("crossingTheLine3"), Sound.ENTITY_BLAZE_DEATH);
CDTimeAPI.setPlayerCD(uuid,"crossingClick",3000);
}
} else {
player.playSound(player.getLocation(),Sound.BLOCK_COMPARATOR_CLICK,1,1);
if(DemonAPI.itemIsNull(stack)){
return;
}
if(!DemonAPI.itemIsLore(stack)){
player.getInventory().addItem(StackUtil.removeTagStack(stack));
inv.setItem(rawSlot, DemonAPI.glass(8,"§7[§c空§7]"));
return;
}
ItemStack cursor = e.getCursor();
if(DemonAPI.itemIsNull(cursor) || DemonAPI.itemIsLore(cursor)){
return;
}
inv.setItem(rawSlot, StackUtil.addTagStack(cursor, player.getName()));
e.setCursor(new ItemStack(Material.AIR));
}
}
if(tradeData.getTarget().equals(player)){
if(!isClickValidPlace(true,rawSlot)){
if(rawSlot == 41 || rawSlot == 42 || rawSlot == 43 || rawSlot == 44){
if(tradeData.getState(player).equals(TradeState.CONFIRM)){
return;
}
tradeData.setStateData(player,TradeState.CONFIRM);
if(tradeData.isMutualComfirm()){
// 执行交易操作
tradeData.successTrade();
InviteManager.tradeData.remove(tradeData);
} else {
confirmGlassState(inv, true);
MessageUtil.sendMessage(player,Config.getString("ConfirmTheTrade"), Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
MessageUtil.sendMessage(tradeData.getPlayer(), Config.getString("ConfirmTheTrade2"), Sound.ENTITY_CAT_AMBIENT);
}
return;
}
if(CDTimeAPI.isCD(uuid,"crossingClick")) {
tradeData.setTradeBreakTheLaw(true);
MessageUtil.sendMessage(player, Config.getString("crossingTheLine"), Sound.ENTITY_BLAZE_DEATH);
MessageUtil.sendMessage(tradeData.getPlayer(), Config.getString("crossingTheLine2").replace("{name}", player.getName()), Sound.ENTITY_BLAZE_DEATH);
player.closeInventory();
} else {
MessageUtil.sendMessage(player, Config.getString("crossingTheLine3"), Sound.ENTITY_BLAZE_DEATH);
CDTimeAPI.setPlayerCD(uuid,"crossingClick",3000);
}
} else {
player.playSound(player.getLocation(),Sound.BLOCK_COMPARATOR_CLICK,1,1);
if(DemonAPI.itemIsNull(stack)){
return;
}
if(!DemonAPI.itemIsLore(stack)){
player.getInventory().addItem(StackUtil.removeTagStack(stack));
inv.setItem(rawSlot, DemonAPI.glass(8,"§7[§c空§7]"));
return;
}
ItemStack cursor = e.getCursor();
if(DemonAPI.itemIsNull(cursor) || DemonAPI.itemIsLore(cursor)){
return;
}
inv.setItem(rawSlot, StackUtil.addTagStack(cursor, player.getName()));
e.setCursor(new ItemStack(Material.AIR));
}
}
}
}
}
public boolean isClickValidPlace(boolean targetD, int rawSlot){
if(targetD){
for (int slot : Config.targetSlots){
if(rawSlot == slot){
return true;
}
}
} else {
for (int slot : Config.playerSlots) {
if (rawSlot == slot) {
return true;
}
}
}
return false;
}
public void confirmGlassState(Inventory inv,boolean targetD){
ItemStack stack = DemonAPI.glass(5,"§c§l 已锁定交易品");
ItemMeta meta = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("§7按下 §c§lESC §7取消交易");
meta.setLore(lore);
stack.setItemMeta(meta);
if(targetD){
for (int slot : Config.targetButts){
inv.setItem(slot,stack);
}
} else {
for (int slot : Config.playerButts){
inv.setItem(slot,stack);
}
}
}
@EventHandler
public void onClose(InventoryCloseEvent e){
Player player = (Player) e.getPlayer();
Inventory inv = e.getInventory();
if(e.getView().getTitle().equalsIgnoreCase(Config.invTitle)){
TradeData tradeData = InviteManager.getTradeData(player);
if(tradeData == null){
return;
}
if(tradeData.isTradeStop()){
return;
}
if(tradeData.getPlayer().equals(player)){
tradeData.closeTradeGui(true);
}else if(tradeData.getTarget().equals(player)){
tradeData.closeTradeGui(false);
}
InviteManager.tradeData.remove(tradeData);
}
}
}

View File

@ -0,0 +1,30 @@
package com.yaohun.trade.listener;
import com.yaohun.trade.data.TradeData;
import com.yaohun.trade.manage.InviteManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
public class PlayerListener implements Listener {
@EventHandler
public void onQuit(PlayerQuitEvent e){
Player player = e.getPlayer();
TradeData tradeData = InviteManager.getTradeData(player);
if(tradeData == null){
return;
}
if(tradeData.isTradeStop()){
return;
}
if(tradeData.getPlayer().equals(player)){
tradeData.closeTradeGui(true);
}else if(tradeData.getTarget().equals(player)){
tradeData.closeTradeGui(false);
}
InviteManager.tradeData.remove(tradeData);
System.out.printf("[日志 - 交易] 玩家 "+player.getName()+" 因退出游戏导致交易终止.");
}
}

View File

@ -0,0 +1,187 @@
package com.yaohun.trade.manage;
import com.yaohun.trade.config.Config;
import com.yaohun.trade.data.InviteData;
import com.yaohun.trade.data.TradeData;
import com.yaohun.trade.gui.GuiMain;
import com.yaohun.trade.gui.TradeGui;
import com.yaohun.trade.util.MessageUtil;
import com.yaohun.trade.util.TradeState;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.Util.AreaType;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.util.*;
public class InviteManager {
public static final List<TradeData> tradeData = new ArrayList<>();
private static final Map<String, InviteData> inviteData = new HashMap<>();
public static TradeData getTradeData(Player player) {
for (TradeData tradeData : tradeData) {
if (tradeData.getPlayer().equals(player)) {
return tradeData;
}else if (tradeData.getTarget().equals(player)) {
return tradeData;
}
}
return null;
}
private static boolean isInviteExit(Player player){
return inviteData.containsKey(player.getName());
}
private static boolean isInviteTargetExit(Player target){
for (InviteData inviteData : inviteData.values()){
if (inviteData.getTarget().equals(target)){
return true;
}
}
return false;
}
public static InviteData getInviteData(Player player) {
for (InviteData inviteData : inviteData.values()){
if (inviteData.getTarget().equals(player)) {
return inviteData;
}else if (inviteData.getPlayer().equals(player)) {
return inviteData;
}
}
return null;
}
public static void sendInvite(Player player,Player target) {
String playerName = player.getName();
// 判断目标是否存在交易请求尚未处理
if(isInviteTargetExit(target)){
String message = Config.getString("targetNotProcessedYet").replace("{target}", target.getName());
MessageUtil.sendMessage(player, message, Sound.ENTITY_VILLAGER_NO);
return;
}
// 玩家若已创建交易请求,则无法再次创建
if(isInviteExit(player)){
InviteData data = inviteData.get(playerName);
// 判断上一个创建的交易请求是否已超时
if(!data.isExpired()) {
String message = Config.getString("inviteAlreadyExist").replace("{target}", target.getName());
MessageUtil.sendMessage(player, message, Sound.ENTITY_VILLAGER_NO);
return;
}
}
InviteData data = new InviteData(player, target);
String targetName = target.getName();
inviteData.put(playerName, data);
String sendAnInvitation = Config.getString("sendAnInvitation").replace("{target}", targetName);
MessageUtil.sendMessage(player, sendAnInvitation, Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
String receivedAnInvitation = Config.getString("receivedAnInvitation").replace("{player}", playerName);
MessageUtil.sendMessage(target, receivedAnInvitation, Sound.ENTITY_EXPERIENCE_ORB_PICKUP);
if (DemonAPI.getAreaType() == AreaType.DEFAULT) {
MessageUtil.sendClickMessage(target, "§r §a§l【点击同意】 §r", "trade accept");
MessageUtil.sendClickMessage(target, "§r §c§l【点击拒绝】 §r", "trade deny");
} else {
MessageUtil.sendClickMessage(target, "§r §a§l【點擊同意】 §r", "trade accept");
MessageUtil.sendClickMessage(target, "§r §c§l【點擊拒絕】 §r", "trade deny");
}
GuiMain.OpenGui(target,playerName);
}
public static void acceptInvite(Player target) {
String targetName = target.getName();
InviteData data = getInviteData(target);
// 判断玩家是否有交易需要处理
if (data == null) {
MessageUtil.sendMessage(target, Config.getString("inviteNotExist"), Sound.ENTITY_VILLAGER_NO);
return;
}
String playerName = data.playerName();
// 判断这个交易请求是否已过期
if(data.isExpired()){
MessageUtil.sendMessage(target, Config.getString("inviteExpire"), Sound.ENTITY_VILLAGER_NO);
inviteData.remove(playerName);
return;
}
inviteData.remove(playerName);
// 判断发起玩家是否已离线
Player player = Bukkit.getPlayer(playerName);
if(player == null || !player.isOnline()){
MessageUtil.sendMessage(target, Config.getString("invitePlayerOffline"), Sound.ENTITY_VILLAGER_NO);
return;
}
// 判断发起玩家和接收玩家是否是同一人
if(player.equals(target)){
MessageUtil.sendMessage(target, Config.getString("inviteNotSelf"), Sound.ENTITY_VILLAGER_NO);
return;
}
// 判断两人距离是否已超出距离
if(hasDistance(player, target)){
String message = Config.getString("inviteDistanceLimit").replace("{distance}", String.valueOf(Config.getLimitDistance()));
MessageUtil.sendMessage(target, message, Sound.ENTITY_VILLAGER_NO);
return;
}
// 打开交易界面进行交易
String message = Config.getString("inviteSuccess");
MessageUtil.sendMessage(target, message.replace("{name}",playerName),Sound.BLOCK_CHEST_OPEN);
MessageUtil.sendMessage(player, message.replace("{name}",targetName),Sound.BLOCK_CHEST_OPEN);
/*打开界面*/
Inventory gui = new TradeGui(player,target).getInventory();
player.openInventory(gui);
target.openInventory(gui);
tradeData.add(new TradeData(player,target,gui));
// player.openInventory(player.getEnderChest());
}
public static void denyInvite(Player target) {
InviteData data = getInviteData(target);
// 判断玩家是否有交易需要处理
if (data == null) {
MessageUtil.sendMessage(target, Config.getString("inviteNotExist"), Sound.ENTITY_VILLAGER_NO);
return;
}
String playerName = data.playerName();
// 判断这个交易请求是否已过期
if(data.isExpired()){
MessageUtil.sendMessage(target, Config.getString("inviteExpire"), Sound.ENTITY_VILLAGER_NO);
inviteData.remove(playerName);
return;
}
inviteData.remove(playerName);
// 判断发起玩家是否已离线
Player player = Bukkit.getPlayer(playerName);
if(player == null || !player.isOnline()){
MessageUtil.sendMessage(target, Config.getString("invitePlayerOffline"), Sound.ENTITY_VILLAGER_NO);
return;
}
// 判断发起玩家和接收玩家是否是同一人
if(player.equals(target)){
MessageUtil.sendMessage(target, Config.getString("inviteNotSelf"), Sound.ENTITY_VILLAGER_NO);
return;
}
String sendMessage = Config.getString("inviteDenySend").replace("{target}", target.getName());
MessageUtil.sendMessage(player, sendMessage);
String targetMessage = Config.getString("inviteDenyTarget").replace("{player}", playerName);
MessageUtil.sendMessage(target, targetMessage);
}
private static boolean hasDistance(Player player, Player target){
Location locA = player.getLocation();
Location locB = target.getLocation();
if(!locA.getWorld().equals(locB.getWorld())){
return true;
}
double distance = locA.distance(locB);
if(distance >= Config.getLimitDistance()){
return true;
}
return false;
}
}

View File

@ -0,0 +1,61 @@
package com.yaohun.trade.manage;
import com.yaohun.trade.data.TradeLogData;
import me.Demon.DemonPlugin.DemonAPI;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class LogsManager {
private File file;
private FileConfiguration config;
private List<TradeLogData> logDataList = new ArrayList<>();
public LogsManager() {
String pathData = "plugins/AuLogs/TradeLog";
File path = new File(pathData);
if(!path.exists()){
path.mkdirs();
}
this.file = new File(pathData, DemonAPI.getTime("yyyy-MM")+".yml");
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
this.config = YamlConfiguration.loadConfiguration(this.file);
}
public void addLogData(TradeLogData logData){
this.logDataList.add(logData);
}
public void saveAllLog(){
if(logDataList.isEmpty()){
return;
}
for (TradeLogData logData : logDataList){
String tradeId = logData.getTradeID();
this.config.set(tradeId+".时间",DemonAPI.LongToStringData(logData.getTradeTime(),"yyyy-MM-dd HH:mm:ss"));
this.config.set(tradeId+".发起者",logData.getPlayerName());
this.config.set(tradeId+".发起者物品",logData.getPlayerList());
this.config.set(tradeId+".接收者",logData.getTargetName());
this.config.set(tradeId+".接收者物品",logData.getTargetList());
}
try {
this.config.save(this.file);
} catch (IOException e) {
throw new RuntimeException(e);
}
Bukkit.getConsoleSender().sendMessage("§6[交易系统] §7成功保存交易日志: §a"+logDataList.size()+"");
}
}

View File

@ -0,0 +1,31 @@
package com.yaohun.trade.util;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Sound;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class MessageUtil {
public static void sendClickMessage(Player player, String message,String command){
TextComponent tomessage = new TextComponent(message);
tomessage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/"+command));
tomessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("§a极§b光§c像§d素").create()));
player.spigot().sendMessage(tomessage);
}
public static void sendMessage(CommandSender sender, String message) {
sender.sendMessage(message);
}
public static void sendMessage(CommandSender sender, String message, Sound sound) {
sender.sendMessage(message);
if(sender instanceof Player){
Player player = (Player) sender;
player.playSound(player.getLocation(), sound, 0.8f,1.2f);
}
}
}

View File

@ -0,0 +1,23 @@
package com.yaohun.trade.util;
import me.Demon.DemonPlugin.Util.RandomUtil;
import me.Demon.DemonPlugin.data.NbtItem;
import org.bukkit.inventory.ItemStack;
public class StackUtil {
public static ItemStack addTagStack(ItemStack stack, String ownerName){
NbtItem nbtItem = new NbtItem(stack);
nbtItem.setString("tradeTag",ownerName+"#"+ RandomUtil.getRandomInt(1000,8000));
return nbtItem.getItem();
}
public static ItemStack removeTagStack(ItemStack stack){
NbtItem nbtItem = new NbtItem(stack);
if(nbtItem.hasKey("tradeTag")) {
nbtItem.removeKey("tradeTag");
return nbtItem.getItem();
}
return stack;
}
}

View File

@ -0,0 +1,7 @@
package com.yaohun.trade.util;
public enum TradeState {
OPEN,
CONFIRM,
SUCCEED
}

View File

@ -0,0 +1,28 @@
Message:
commandUsageInvite: "§f[§c系统§f] §a正确用法: §e/trade [玩家名]"
breakchest: "§f[§c系统§f] §a请将箱子中的物品取出后再尝试破坏."
invitePlayerOffline: "§f[§c系统§f] §a目标玩家貌似不存在或已离线."
targetNotProcessedYet: "§f[§c系统§f] §a玩家 §e{target} §a存在尚未处理的交易请求."
inviteAlreadyExist: "§f[§c系统§f] §a你已经想玩家 §e{target} §a发送过交易请求."
sendAnInvitation: "§f[§c系统§f] §a发送成功,已向 §e{target} §a发出交易请求."
receivedAnInvitation: "§f[§c系统§f] §a你收到了来自 §e{player} §a的交易请求."
inviteNotExist: "§f[§c系统§f] §a没有需要处理的交易请求."
inviteExpire: "§f[§c系统§f] §a这个交易请求貌似已过期."
inviteNotSelf: "§f[§c系统§f] §a处理失败,无法同意自己的交易请求."
inviteDistanceLimit: "§f[§c系统§f] §a处理失败,交易双方都需要在§e<{distance}格>§a方块内."
inviteSuccess: "§f[§c系统§f] §a您正在与 §e{name} §a进行交易."
inviteDenySend: "§f[§c系统§f] §a玩家 §e{target} §a拒绝了你发起的交易请求."
inviteDenyTarget: "§f[§c系统§f] §a你婉拒了来自 §e{player} §a的交易请求."
crossingTheLine: "§f[§c系统§f] §b交易取消,因为你误触到了不属于你的操作区."
crossingTheLine2: "§f[§c系统§f] §b交易取消,因玩家 §e{name} §b进行了越界违规操作."
crossingTheLine3: "§f[§c系统§f] §b亲,你点击的位置并不是你的操作区."
ConfirmTheTrade: "§f[§c系统§f] §a成功确认交易请耐心等待交易方确认."
ConfirmTheTrade2: "§f[§c系统§f] §a交易方已确认交易请尽快确认完成交易."
insufficientSpace: "§f[§c系统§f] §b交易取消,发起交易方没有足够的空间放入交易品."
insufficientSpace2: "§f[§c系统§f] §b交易取消,接受交易方没有足够的空间放入交易品."
closeTheInterface: "§f[§c系统§f] §b成功取消与 §e{name} §b的交易事件."
closeTheInterface2: "§f[§c系统§f] §b玩家 §e{name} §b取消了与你的交易."
doubleClickAnit: "§f[§c系统§f] §b交易取消,交易系统不支持双击点击."
shfitClickAnit: "§f[§c系统§f] §b交易取消,交易系统不支持SHIFT点击."
CompleteTrade: "§f[§c系统§f] §6交易成功,您获得了 §a{count}件 §6交易物品."
CompleteTrade2: "§f[§c系统§f] §6交易成功,物品已发送至对方背包."

View File

@ -0,0 +1,4 @@
BreakChest:
enabled: true
worlds:
- PlotSquared

View File

@ -0,0 +1,8 @@
name: DemonTrade
main: com.yaohun.trade.TradeMain
version: 1.0.0
author: yaohun
depend:
- DemonAPI
commands:
trade: