Upload folder via GUI - src
This commit is contained in:
@@ -92,6 +92,12 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
private Map<Integer, OrderData> orderCache = new HashMap<>();
|
private Map<Integer, OrderData> orderCache = new HashMap<>();
|
||||||
private Map<UUID, Integer> activeOrderIds = new ConcurrentHashMap<>();
|
private Map<UUID, Integer> activeOrderIds = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// Gift-System: Ausstehende Geschenk-Anfragen (Empfänger-UUID → OrderData)
|
||||||
|
private final Map<UUID, GiftRequest> pendingGiftRequests = new ConcurrentHashMap<>();
|
||||||
|
// URL für Geschenk-Endpoint und Rückerstattungs-Endpoint
|
||||||
|
private String wpUrlGiftAccept;
|
||||||
|
private String wpUrlGiftDecline;
|
||||||
|
|
||||||
private FlyManager flyManager;
|
private FlyManager flyManager;
|
||||||
private FlyCodeManager flyCodeManager;
|
private FlyCodeManager flyCodeManager;
|
||||||
private RankManager rankManager;
|
private RankManager rankManager;
|
||||||
@@ -134,6 +140,8 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
wpUrlCancel = wpBase + "/cancel_order";
|
wpUrlCancel = wpBase + "/cancel_order";
|
||||||
wpUrlSellItems = wpBase + "/sell_items";
|
wpUrlSellItems = wpBase + "/sell_items";
|
||||||
wpUrlSell = wpBase + "/sell_item";
|
wpUrlSell = wpBase + "/sell_item";
|
||||||
|
wpUrlGiftAccept = wpBase + "/gift_accept";
|
||||||
|
wpUrlGiftDecline = wpBase + "/gift_decline";
|
||||||
|
|
||||||
targetServer = getConfig().getString("server-name", "survival").toLowerCase();
|
targetServer = getConfig().getString("server-name", "survival").toLowerCase();
|
||||||
currency = getConfig().getString("currency-name", "Coins");
|
currency = getConfig().getString("currency-name", "Coins");
|
||||||
@@ -280,7 +288,6 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
"Spieler " + p.getName() + " hat aktive Order – überspringe.");
|
"Spieler " + p.getName() + " hat aktive Order – überspringe.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Join-Fetch läuft noch – nicht parallel pollen
|
|
||||||
Long cooldown = joinFetchCooldown.get(p.getUniqueId());
|
Long cooldown = joinFetchCooldown.get(p.getUniqueId());
|
||||||
if (cooldown != null && System.currentTimeMillis() < cooldown) {
|
if (cooldown != null && System.currentTimeMillis() < cooldown) {
|
||||||
if (debug) getLogger().info(
|
if (debug) getLogger().info(
|
||||||
@@ -328,20 +335,27 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
String itemTitle = order.get("item_title").getAsString();
|
String itemTitle = order.get("item_title").getAsString();
|
||||||
double price = order.get("price").getAsDouble();
|
double price = order.get("price").getAsDouble();
|
||||||
|
|
||||||
// Atomar: nur wenn noch keine aktive Order → eintragen und GUI öffnen
|
// Gift-Empfänger auslesen – leer bei normalen Käufen
|
||||||
// synchronized auf activeOrderIds verhindert Race Condition zwischen zwei Async-Threads
|
String giftRecipient = (order.has("gift_recipient")
|
||||||
|
&& !order.get("gift_recipient").isJsonNull())
|
||||||
|
? order.get("gift_recipient").getAsString().trim() : "";
|
||||||
|
|
||||||
|
// Spieler A bestätigt IMMER zuerst selbst (verhindert Missbrauch).
|
||||||
|
// giftRecipient wird in OrderData gespeichert und erst nach
|
||||||
|
// Bestätigung + Geld-Abbuchung an Spieler B weitergeleitet.
|
||||||
synchronized (activeOrderIds) {
|
synchronized (activeOrderIds) {
|
||||||
if (activeOrderIds.containsKey(p.getUniqueId())) {
|
if (activeOrderIds.containsKey(p.getUniqueId())) {
|
||||||
if (debug) getLogger().info(
|
if (debug) getLogger().info(
|
||||||
"Order #" + id + " für " + p.getName() + " ignoriert (bereits aktiv).");
|
"Order #" + id + " für " + p.getName() + " ignoriert (bereits aktiv).");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OrderData data = new OrderData(id, "multi_item", itemTitle, price, 1, jsonResponse);
|
OrderData data = new OrderData(id, "multi_item", itemTitle,
|
||||||
|
price, 1, jsonResponse, giftRecipient);
|
||||||
orderCache.put(id, data);
|
orderCache.put(id, data);
|
||||||
activeOrderIds.put(p.getUniqueId(), id);
|
activeOrderIds.put(p.getUniqueId(), id);
|
||||||
}
|
}
|
||||||
Bukkit.getScheduler().runTask(IngameShopSpigot.this,
|
Bukkit.getScheduler().runTask(IngameShopSpigot.this,
|
||||||
() -> openConfirmGUI(p, id, itemTitle, price, jsonResponse));
|
() -> openConfirmGUI(p, id, itemTitle, price, jsonResponse, giftRecipient));
|
||||||
}
|
}
|
||||||
} else if (responseCode == 401) {
|
} else if (responseCode == 401) {
|
||||||
getLogger().warning("❌ API-Key ungültig! HTTP 401 von " + endpointUrl);
|
getLogger().warning("❌ API-Key ungültig! HTTP 401 von " + endpointUrl);
|
||||||
@@ -351,6 +365,224 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// GIFT-SYSTEM
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wird aufgerufen wenn eine Order ein gift_recipient-Feld hat.
|
||||||
|
* Leitet die Anfrage an den Empfänger (Spieler B) weiter.
|
||||||
|
* Falls Spieler B offline → Order bleibt pending (wird beim nächsten Join geholt).
|
||||||
|
*/
|
||||||
|
private void handleIncomingGift(String senderName, String recipientName,
|
||||||
|
int orderId, String itemTitle,
|
||||||
|
double price, String jsonResponse) {
|
||||||
|
Player recipient = Bukkit.getPlayerExact(recipientName);
|
||||||
|
if (recipient == null || !recipient.isOnline()) {
|
||||||
|
// Empfänger offline – Order bleibt pending, beim Join wird sie erneut gepollt
|
||||||
|
if (debug) getLogger().info(
|
||||||
|
"[Gift] Empfänger " + recipientName + " offline – warte auf Join.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empfänger bereits mit offener Gift-Anfrage?
|
||||||
|
if (pendingGiftRequests.containsKey(recipient.getUniqueId())) {
|
||||||
|
if (debug) getLogger().info(
|
||||||
|
"[Gift] " + recipientName + " hat bereits eine offene Gift-Anfrage.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GiftRequest req = new GiftRequest(orderId, senderName, recipientName,
|
||||||
|
itemTitle, price, jsonResponse);
|
||||||
|
pendingGiftRequests.put(recipient.getUniqueId(), req);
|
||||||
|
orderCache.put(orderId, new OrderData(orderId, "multi_item", itemTitle, price, 1, jsonResponse));
|
||||||
|
|
||||||
|
// Order auf WP auf 'processing' setzen damit sie nicht nochmal gepollt wird
|
||||||
|
// (A hat bereits bezahlt, B muss nur noch annehmen/ablehnen)
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
try {
|
||||||
|
HttpURLConnection conn = openAuthConnection(wpUrlExecute, "POST");
|
||||||
|
writeJson(conn, "{\"id\":\"" + orderId + "\"}");
|
||||||
|
conn.getResponseCode();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debug) getLogger().log(Level.WARNING, "[Gift] Status-Update Fehler", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(this);
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask(this, () -> openGiftConfirmGUI(recipient, req));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Öffnet dem Empfänger das Gift-Bestätigungs-GUI */
|
||||||
|
private void openGiftConfirmGUI(Player recipient, GiftRequest req) {
|
||||||
|
Inventory gui = Bukkit.createInventory(null, 27, GUI_GIFT_TITLE);
|
||||||
|
|
||||||
|
ItemStack pane = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
|
||||||
|
ItemMeta pM = pane.getItemMeta();
|
||||||
|
pM.setDisplayName(" ");
|
||||||
|
pane.setItemMeta(pM);
|
||||||
|
for (int i = 0; i < 27; i++) gui.setItem(i, pane);
|
||||||
|
|
||||||
|
// Info-Item in der Mitte
|
||||||
|
Material icon = getFirstItemMaterial(req.jsonPayload);
|
||||||
|
ItemStack info = new ItemStack(icon);
|
||||||
|
ItemMeta infoMeta = info.getItemMeta();
|
||||||
|
infoMeta.setDisplayName(ChatColor.GOLD + "" + ChatColor.BOLD + req.itemTitle);
|
||||||
|
infoMeta.setLore(Arrays.asList(
|
||||||
|
ChatColor.GRAY + "──────────────────",
|
||||||
|
ChatColor.WHITE + "Von: " + ChatColor.YELLOW + req.senderName,
|
||||||
|
ChatColor.WHITE + "Wert: " + ChatColor.YELLOW + req.price + " " + currency,
|
||||||
|
ChatColor.GRAY + "──────────────────",
|
||||||
|
ChatColor.GREEN + "🎁 Du hast ein Geschenk erhalten!",
|
||||||
|
ChatColor.GRAY + "Annehmen oder ablehnen?"
|
||||||
|
));
|
||||||
|
info.setItemMeta(infoMeta);
|
||||||
|
|
||||||
|
// Annehmen
|
||||||
|
ItemStack yes = new ItemStack(Material.LIME_WOOL);
|
||||||
|
ItemMeta yM = yes.getItemMeta();
|
||||||
|
yM.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD + "✔ Annehmen");
|
||||||
|
yM.setLore(Arrays.asList(ChatColor.GRAY + "Geschenk wird dir übergeben"));
|
||||||
|
yes.setItemMeta(yM);
|
||||||
|
|
||||||
|
// Ablehnen
|
||||||
|
ItemStack no = new ItemStack(Material.RED_WOOL);
|
||||||
|
ItemMeta nM = no.getItemMeta();
|
||||||
|
nM.setDisplayName(ChatColor.RED + "" + ChatColor.BOLD + "✘ Ablehnen");
|
||||||
|
nM.setLore(Arrays.asList(
|
||||||
|
ChatColor.GRAY + "Bestellung wird storniert,",
|
||||||
|
ChatColor.GRAY + req.senderName + " erhält sein Geld zurück"
|
||||||
|
));
|
||||||
|
no.setItemMeta(nM);
|
||||||
|
|
||||||
|
gui.setItem(13, info);
|
||||||
|
gui.setItem(11, yes);
|
||||||
|
gui.setItem(15, no);
|
||||||
|
recipient.openInventory(gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Empfänger nimmt Geschenk an → Ware ausliefern */
|
||||||
|
private void acceptGift(Player recipient, GiftRequest req) {
|
||||||
|
// pendingGiftRequests wurde bereits im Click-Handler entfernt (vor closeInventory)
|
||||||
|
|
||||||
|
// "__GIFT_DELIVERY__" signalisiert executeShopLogic: kein Geldabzug, kein incomeReceiver
|
||||||
|
// (Geld wurde bereits bei A's Bestätigung abgezogen)
|
||||||
|
final OrderData deliverData = new OrderData(req.orderId, "multi_item", req.itemTitle,
|
||||||
|
req.price, 1, req.jsonPayload, "__GIFT_DELIVERY__");
|
||||||
|
|
||||||
|
recipient.sendMessage(ChatColor.GREEN + "🎁 Du hast das Geschenk von "
|
||||||
|
+ ChatColor.YELLOW + req.senderName
|
||||||
|
+ ChatColor.GREEN + " angenommen!");
|
||||||
|
|
||||||
|
// Ware direkt ausliefern (Geld wurde bereits von Käufer A abgezogen)
|
||||||
|
// executeShopLogic ruft intern markOrderCompleted auf → WP-Status wird 'completed'
|
||||||
|
executeShopLogic(recipient, deliverData, req.orderId);
|
||||||
|
|
||||||
|
// Sender benachrichtigen falls online
|
||||||
|
Player sender = Bukkit.getPlayerExact(req.senderName);
|
||||||
|
if (sender != null && sender.isOnline()) {
|
||||||
|
sender.sendMessage(ChatColor.GREEN + "🎁 " + ChatColor.YELLOW + recipient.getName()
|
||||||
|
+ ChatColor.GREEN + " hat dein Geschenk angenommen!");
|
||||||
|
sender.playSound(sender.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0F, 1.2F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Empfänger lehnt Geschenk ab → Stornierung + Rückerstattung an Käufer */
|
||||||
|
private void declineGift(Player recipient, GiftRequest req) {
|
||||||
|
pendingGiftRequests.remove(recipient.getUniqueId());
|
||||||
|
orderCache.remove(req.orderId);
|
||||||
|
|
||||||
|
recipient.sendMessage(ChatColor.YELLOW + "❌ Geschenk abgelehnt.");
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
try {
|
||||||
|
// 1) Order auf WordPress stornieren
|
||||||
|
HttpURLConnection conn = openAuthConnection(wpUrlGiftDecline, "POST");
|
||||||
|
writeJson(conn, "{\"id\":\"" + req.orderId + "\""
|
||||||
|
+ ",\"sender\":\"" + req.senderName + "\""
|
||||||
|
+ ",\"price\":" + (int) req.price + "}");
|
||||||
|
int code = conn.getResponseCode();
|
||||||
|
if (debug) getLogger().info(
|
||||||
|
"[Gift] Decline HTTP " + code + " für Order #" + req.orderId);
|
||||||
|
|
||||||
|
// 2) Rückerstattung an Käufer (Vault)
|
||||||
|
Bukkit.getScheduler().runTask(IngameShopSpigot.this, () -> {
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
org.bukkit.OfflinePlayer buyer =
|
||||||
|
Bukkit.getOfflinePlayerIfCached(req.senderName);
|
||||||
|
if (buyer == null) {
|
||||||
|
for (org.bukkit.OfflinePlayer op : Bukkit.getOfflinePlayers()) {
|
||||||
|
if (op.getName() != null
|
||||||
|
&& op.getName().equalsIgnoreCase(req.senderName)) {
|
||||||
|
buyer = op;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buyer != null) {
|
||||||
|
econ.depositPlayer(buyer, req.price);
|
||||||
|
if (debug) getLogger().info(
|
||||||
|
"[Gift] Rückerstattung " + req.price + " " + currency
|
||||||
|
+ " an " + req.senderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Käufer benachrichtigen falls online
|
||||||
|
Player senderOnline = Bukkit.getPlayerExact(req.senderName);
|
||||||
|
if (senderOnline != null && senderOnline.isOnline()) {
|
||||||
|
senderOnline.sendMessage(ChatColor.RED
|
||||||
|
+ "🎁 " + ChatColor.YELLOW + recipient.getName()
|
||||||
|
+ ChatColor.RED + " hat dein Geschenk abgelehnt.");
|
||||||
|
senderOnline.sendMessage(ChatColor.GREEN
|
||||||
|
+ "💰 " + req.price + " " + currency
|
||||||
|
+ " wurden dir erstattet.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().log(Level.WARNING, "[Gift] Fehler bei decline", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gift-GUI Polling starten (Empfänger-Polling beim Join)
|
||||||
|
private void checkGiftOrdersForPlayer(Player p) {
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
try {
|
||||||
|
HttpURLConnection conn = openAuthConnection(
|
||||||
|
wpBase + "/pending_gifts?recipient=" + p.getName(), "GET");
|
||||||
|
int code = conn.getResponseCode();
|
||||||
|
if (code != 200) return;
|
||||||
|
String body = readResponse(conn);
|
||||||
|
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||||
|
JsonArray orders = json.getAsJsonArray("orders");
|
||||||
|
if (orders == null || orders.size() == 0) return;
|
||||||
|
|
||||||
|
JsonObject order = orders.get(0).getAsJsonObject();
|
||||||
|
int id = order.get("id").getAsInt();
|
||||||
|
String senderName = order.has("player_name")
|
||||||
|
? order.get("player_name").getAsString() : "?";
|
||||||
|
String orderServer = order.has("server")
|
||||||
|
? order.get("server").getAsString().toLowerCase() : "";
|
||||||
|
if (!orderServer.equals(targetServer)) return;
|
||||||
|
|
||||||
|
String jsonResponse = order.has("response")
|
||||||
|
? order.get("response").getAsString() : "[]";
|
||||||
|
String itemTitle = order.get("item_title").getAsString();
|
||||||
|
double price = order.get("price").getAsDouble();
|
||||||
|
|
||||||
|
handleIncomingGift(senderName, p.getName(), id, itemTitle, price, jsonResponse);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debug) getLogger().log(Level.WARNING, "[Gift] Polling Fehler", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String GUI_GIFT_TITLE = ChatColor.GOLD + "🎁 Geschenk erhalten!";
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// OFFLINE-QUEUE & FLY-RESTORE
|
// OFFLINE-QUEUE & FLY-RESTORE
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
@@ -394,6 +626,11 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}.runTaskAsynchronously(this);
|
}.runTaskAsynchronously(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ausstehende Gift-Orders prüfen (Spieler B ist jetzt online)
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override public void run() { checkGiftOrdersForPlayer(p); }
|
||||||
|
}.runTaskAsynchronously(this);
|
||||||
|
|
||||||
// Ausstehende Fly-Codes anzeigen
|
// Ausstehende Fly-Codes anzeigen
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
@@ -464,8 +701,21 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
if (!(event.getPlayer() instanceof Player)) return;
|
if (!(event.getPlayer() instanceof Player)) return;
|
||||||
Player p = (Player) event.getPlayer();
|
Player p = (Player) event.getPlayer();
|
||||||
|
|
||||||
// Confirm-GUI: bei ESC sofort wieder öffnen
|
// Titel zuerst holen – wird für beide GUI-Checks benötigt
|
||||||
String title = event.getView().getTitle();
|
String title = event.getView().getTitle();
|
||||||
|
|
||||||
|
// Gift-Confirm-GUI: bei ESC sofort wieder öffnen
|
||||||
|
if (GUI_GIFT_TITLE.equals(title) && pendingGiftRequests.containsKey(p.getUniqueId())) {
|
||||||
|
GiftRequest req = pendingGiftRequests.get(p.getUniqueId());
|
||||||
|
if (req != null) {
|
||||||
|
p.sendMessage(ChatColor.YELLOW + "⚠ Bitte nimm das Geschenk an oder lehne es ab!");
|
||||||
|
Bukkit.getScheduler().runTaskLater(this,
|
||||||
|
() -> openGiftConfirmGUI(p, req), 2L);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm-GUI: bei ESC sofort wieder öffnen
|
||||||
if (GUI_CONFIRM_TITLE.equals(title) && activeOrderIds.containsKey(p.getUniqueId())) {
|
if (GUI_CONFIRM_TITLE.equals(title) && activeOrderIds.containsKey(p.getUniqueId())) {
|
||||||
int orderId = activeOrderIds.get(p.getUniqueId());
|
int orderId = activeOrderIds.get(p.getUniqueId());
|
||||||
OrderData data = orderCache.get(orderId);
|
OrderData data = orderCache.get(orderId);
|
||||||
@@ -494,24 +744,40 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
private void openConfirmGUI(Player player, int orderId,
|
private void openConfirmGUI(Player player, int orderId,
|
||||||
String itemTitle, double price, String jsonPayload) {
|
String itemTitle, double price, String jsonPayload) {
|
||||||
|
openConfirmGUI(player, orderId, itemTitle, price, jsonPayload, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openConfirmGUI(Player player, int orderId,
|
||||||
|
String itemTitle, double price,
|
||||||
|
String jsonPayload, String giftRecipient) {
|
||||||
Inventory gui = Bukkit.createInventory(null, 27, GUI_CONFIRM_TITLE);
|
Inventory gui = Bukkit.createInventory(null, 27, GUI_CONFIRM_TITLE);
|
||||||
Material icon = getFirstItemMaterial(jsonPayload);
|
Material icon = getFirstItemMaterial(jsonPayload);
|
||||||
|
|
||||||
|
boolean isGift = giftRecipient != null && !giftRecipient.isEmpty();
|
||||||
|
|
||||||
ItemStack info = new ItemStack(icon);
|
ItemStack info = new ItemStack(icon);
|
||||||
ItemMeta infoMeta = info.getItemMeta();
|
ItemMeta infoMeta = info.getItemMeta();
|
||||||
infoMeta.setDisplayName(ChatColor.GOLD + "" + ChatColor.BOLD + itemTitle);
|
infoMeta.setDisplayName(ChatColor.GOLD + "" + ChatColor.BOLD
|
||||||
infoMeta.setLore(Arrays.asList(
|
+ (isGift ? "🎁 " : "") + itemTitle);
|
||||||
|
List<String> lore = new ArrayList<>(Arrays.asList(
|
||||||
ChatColor.GRAY + "──────────────────",
|
ChatColor.GRAY + "──────────────────",
|
||||||
ChatColor.WHITE + "Preis: " + ChatColor.YELLOW + price + " " + currency,
|
ChatColor.WHITE + "Preis: " + ChatColor.YELLOW + price + " " + currency
|
||||||
ChatColor.GRAY + "──────────────────",
|
|
||||||
ChatColor.GRAY + "Klicke Grün zum Bestätigen",
|
|
||||||
ChatColor.GRAY + "Klicke Rot zum Abbrechen"
|
|
||||||
));
|
));
|
||||||
|
if (isGift) {
|
||||||
|
lore.add(ChatColor.LIGHT_PURPLE + "Geschenk für: "
|
||||||
|
+ ChatColor.WHITE + giftRecipient);
|
||||||
|
lore.add(ChatColor.GRAY + "Der Empfänger muss ingame annehmen.");
|
||||||
|
}
|
||||||
|
lore.add(ChatColor.GRAY + "──────────────────");
|
||||||
|
lore.add(ChatColor.GRAY + "Klicke Grün zum Bestätigen");
|
||||||
|
lore.add(ChatColor.GRAY + "Klicke Rot zum Abbrechen");
|
||||||
|
infoMeta.setLore(lore);
|
||||||
info.setItemMeta(infoMeta);
|
info.setItemMeta(infoMeta);
|
||||||
|
|
||||||
ItemStack yes = new ItemStack(Material.LIME_WOOL);
|
ItemStack yes = new ItemStack(Material.LIME_WOOL);
|
||||||
ItemMeta yM = yes.getItemMeta();
|
ItemMeta yM = yes.getItemMeta();
|
||||||
yM.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD + "✔ JA, kaufen!");
|
yM.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD
|
||||||
|
+ (isGift ? "🎁 JA, verschenken!" : "✔ JA, kaufen!"));
|
||||||
yM.setLore(Arrays.asList(
|
yM.setLore(Arrays.asList(
|
||||||
ChatColor.GRAY + "" + price + " " + currency + " werden abgezogen"));
|
ChatColor.GRAY + "" + price + " " + currency + " werden abgezogen"));
|
||||||
yes.setItemMeta(yM);
|
yes.setItemMeta(yM);
|
||||||
@@ -565,6 +831,28 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
public void onInventoryClick(InventoryClickEvent event) {
|
public void onInventoryClick(InventoryClickEvent event) {
|
||||||
String title = event.getView().getTitle();
|
String title = event.getView().getTitle();
|
||||||
|
|
||||||
|
// ── Gift-Bestätigen GUI ────────────────────────────────────────────
|
||||||
|
if (GUI_GIFT_TITLE.equals(title)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
if (!(event.getWhoClicked() instanceof Player)) return;
|
||||||
|
Player p = (Player) event.getWhoClicked();
|
||||||
|
int slot = event.getRawSlot();
|
||||||
|
GiftRequest req = pendingGiftRequests.get(p.getUniqueId());
|
||||||
|
if (req == null) { p.closeInventory(); return; }
|
||||||
|
if (slot == 11) {
|
||||||
|
// ERST aus pendingGiftRequests entfernen, DANN closeInventory –
|
||||||
|
// sonst triggert onInventoryClose das GUI erneut
|
||||||
|
pendingGiftRequests.remove(p.getUniqueId());
|
||||||
|
p.closeInventory();
|
||||||
|
acceptGift(p, req);
|
||||||
|
} else if (slot == 15) {
|
||||||
|
pendingGiftRequests.remove(p.getUniqueId());
|
||||||
|
p.closeInventory();
|
||||||
|
declineGift(p, req);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ── Sell GUI ──────────────────────────────────────────────────────
|
// ── Sell GUI ──────────────────────────────────────────────────────
|
||||||
if (handleSellClick(event)) return;
|
if (handleSellClick(event)) return;
|
||||||
|
|
||||||
@@ -840,18 +1128,21 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
private void executeShopLogic(Player player, OrderData data, int orderId) {
|
private void executeShopLogic(Player player, OrderData data, int orderId) {
|
||||||
try {
|
try {
|
||||||
|
// Bei Geschenk-Lieferung an B: kein Geldabzug – Geld wurde bereits von A abgezogen
|
||||||
|
boolean isGiftDelivery = data.giftRecipient != null && data.giftRecipient.equals("__GIFT_DELIVERY__");
|
||||||
|
if (!isGiftDelivery) {
|
||||||
if (econ.getBalance(player) < data.price) {
|
if (econ.getBalance(player) < data.price) {
|
||||||
player.sendMessage(ChatColor.RED + "❌ Nicht genug "
|
player.sendMessage(ChatColor.RED + "❌ Nicht genug "
|
||||||
+ currency + "! (Benötigt: " + data.price + ")");
|
+ currency + "! (Benötigt: " + data.price + ")");
|
||||||
cancelOrder(player, orderId);
|
cancelOrder(player, orderId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
econ.withdrawPlayer(player, data.price);
|
econ.withdrawPlayer(player, data.price);
|
||||||
player.sendMessage(ChatColor.GREEN + "💰 " + data.price + " " + currency + " abgezogen.");
|
player.sendMessage(ChatColor.GREEN + "💰 " + data.price + " " + currency + " abgezogen.");
|
||||||
|
}
|
||||||
|
|
||||||
// Einnahmen an Empfänger-Account gutschreiben
|
// Einnahmen an Empfänger-Account gutschreiben (nicht bei Gift-Lieferung – bereits bei A gebucht)
|
||||||
if (!incomeReceiver.isEmpty()) {
|
if (!isGiftDelivery && !incomeReceiver.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
org.bukkit.OfflinePlayer receiver =
|
org.bukkit.OfflinePlayer receiver =
|
||||||
@@ -878,6 +1169,20 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Gift-System: Ware geht an Empfänger B, nicht an Käufer A ──────
|
||||||
|
// Direkt nach Geldabzug prüfen – BEVOR irgendwelche Items/Commands verteilt werden
|
||||||
|
if (!isGiftDelivery && data.giftRecipient != null && !data.giftRecipient.isEmpty()) {
|
||||||
|
player.sendMessage(ChatColor.LIGHT_PURPLE + "🎁 Dein Geschenk wird an "
|
||||||
|
+ ChatColor.WHITE + data.giftRecipient
|
||||||
|
+ ChatColor.LIGHT_PURPLE + " gesendet!");
|
||||||
|
player.sendMessage(ChatColor.GRAY + "Der Empfänger muss es ingame annehmen.");
|
||||||
|
handleIncomingGift(player.getName(), data.giftRecipient,
|
||||||
|
orderId, data.itemTitle, data.price, data.jsonPayload);
|
||||||
|
orderCache.remove(orderId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
JsonElement root = gson.fromJson(data.jsonPayload, JsonElement.class);
|
JsonElement root = gson.fromJson(data.jsonPayload, JsonElement.class);
|
||||||
JsonObject rootObj = root.isJsonObject() ? root.getAsJsonObject() : null;
|
JsonObject rootObj = root.isJsonObject() ? root.getAsJsonObject() : null;
|
||||||
|
|
||||||
@@ -3293,6 +3598,8 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
wpUrlCancel = wpBase + "/cancel_order";
|
wpUrlCancel = wpBase + "/cancel_order";
|
||||||
wpUrlSellItems = wpBase + "/sell_items";
|
wpUrlSellItems = wpBase + "/sell_items";
|
||||||
wpUrlSell = wpBase + "/sell_item";
|
wpUrlSell = wpBase + "/sell_item";
|
||||||
|
wpUrlGiftAccept = wpBase + "/gift_accept";
|
||||||
|
wpUrlGiftDecline = wpBase + "/gift_decline";
|
||||||
|
|
||||||
targetServer = getConfig().getString("server-name", "survival").toLowerCase();
|
targetServer = getConfig().getString("server-name", "survival").toLowerCase();
|
||||||
currency = getConfig().getString("currency-name", "Coins");
|
currency = getConfig().getString("currency-name", "Coins");
|
||||||
@@ -4231,23 +4538,49 @@ public class IngameShopSpigot extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
// GIFT REQUEST DATA CLASS
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
|
private static class GiftRequest {
|
||||||
|
final int orderId;
|
||||||
|
final String senderName, recipientName, itemTitle, jsonPayload;
|
||||||
|
final double price;
|
||||||
|
|
||||||
|
GiftRequest(int orderId, String senderName, String recipientName,
|
||||||
|
String itemTitle, double price, String jsonPayload) {
|
||||||
|
this.orderId = orderId;
|
||||||
|
this.senderName = senderName;
|
||||||
|
this.recipientName = recipientName;
|
||||||
|
this.itemTitle = itemTitle;
|
||||||
|
this.price = price;
|
||||||
|
this.jsonPayload = jsonPayload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
// DATA CLASS
|
// DATA CLASS
|
||||||
// ===========================================================
|
// ===========================================================
|
||||||
|
|
||||||
private static class OrderData {
|
private static class OrderData {
|
||||||
final int id, quantity;
|
final int id, quantity;
|
||||||
final String itemId, itemTitle, jsonPayload;
|
final String itemId, itemTitle, jsonPayload, giftRecipient;
|
||||||
final double price;
|
final double price;
|
||||||
|
|
||||||
OrderData(int id, String itemId, String itemTitle,
|
OrderData(int id, String itemId, String itemTitle,
|
||||||
double price, int quantity, String jsonPayload) {
|
double price, int quantity, String jsonPayload) {
|
||||||
|
this(id, itemId, itemTitle, price, quantity, jsonPayload, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderData(int id, String itemId, String itemTitle,
|
||||||
|
double price, int quantity, String jsonPayload, String giftRecipient) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.itemId = itemId;
|
this.itemId = itemId;
|
||||||
this.itemTitle = itemTitle;
|
this.itemTitle = itemTitle;
|
||||||
this.price = price;
|
this.price = price;
|
||||||
this.quantity = quantity;
|
this.quantity = quantity;
|
||||||
this.jsonPayload = jsonPayload;
|
this.jsonPayload = jsonPayload;
|
||||||
|
this.giftRecipient = giftRecipient != null ? giftRecipient : "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user