821 lines
35 KiB
Java
821 lines
35 KiB
Java
package popa;
|
||
|
||
import org.bukkit.Bukkit;
|
||
import org.bukkit.entity.Player;
|
||
import org.bukkit.event.EventHandler;
|
||
import org.bukkit.event.Listener;
|
||
import org.bukkit.event.player.PlayerJoinEvent;
|
||
import org.bukkit.event.player.PlayerQuitEvent;
|
||
import org.bukkit.plugin.java.JavaPlugin;
|
||
import java.io.IOException;
|
||
import java.net.URI;
|
||
import java.net.http.HttpClient;
|
||
import java.net.http.HttpRequest;
|
||
import java.net.http.HttpResponse;
|
||
import java.time.Duration;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
import java.util.UUID;
|
||
import java.net.InetAddress;
|
||
import java.util.concurrent.Executors;
|
||
import java.util.concurrent.ScheduledExecutorService;
|
||
import java.util.concurrent.TimeUnit;
|
||
import com.google.gson.JsonObject;
|
||
import com.google.gson.JsonArray;
|
||
import com.google.gson.JsonParser;
|
||
import com.google.gson.JsonElement;
|
||
import org.bukkit.inventory.ItemStack;
|
||
import org.bukkit.inventory.PlayerInventory;
|
||
import org.bukkit.Material;
|
||
import com.google.gson.Gson;
|
||
|
||
|
||
public final class popa extends JavaPlugin implements Listener {
|
||
|
||
|
||
private HttpClient httpClient;
|
||
private String apiUrl;
|
||
private String serverIp;
|
||
private String commandsUrl;
|
||
private String inventoryRequestsUrl;
|
||
private String marketplaceUrl;
|
||
private final Map<UUID, Long> playerLoginTimes = new HashMap<>();
|
||
private final Map<UUID, String> playerNames = new HashMap<>();
|
||
private ScheduledExecutorService scheduler;
|
||
private Gson gson;
|
||
|
||
@Override
|
||
public void onEnable() {
|
||
// Создаем или загружаем конфиг
|
||
saveDefaultConfig();
|
||
reloadConfig();
|
||
|
||
// Получаем настройки из конфига
|
||
String apiBase = getConfig().getString("api-base", "http://localhost:8000");
|
||
apiUrl = getConfig().getString("api-url", apiBase + "/api/server/events");
|
||
commandsUrl = getConfig().getString("commands-url", apiBase + "/api/server/commands");
|
||
inventoryRequestsUrl = getConfig().getString("inventory-requests-url", apiBase + "/api/server/inventory/requests");
|
||
serverIp = getConfig().getString("server-ip", getServerIp());
|
||
|
||
// Инициализируем HTTP клиент
|
||
httpClient = HttpClient.newBuilder()
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.connectTimeout(Duration.ofSeconds(10))
|
||
.build();
|
||
|
||
// Инициализируем Gson для работы с JSON
|
||
gson = new Gson();
|
||
|
||
getServer().getPluginManager().registerEvents(this, this);
|
||
|
||
// Запускаем планировщик для проверки команд
|
||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||
scheduler.scheduleAtFixedRate(this::checkAndExecuteCommands, 5, 5, TimeUnit.SECONDS);
|
||
|
||
// Запускаем планировщик для проверки запросов инвентаря
|
||
scheduler.scheduleAtFixedRate(this::checkInventoryRequests, 5, 5, TimeUnit.SECONDS);
|
||
|
||
// Отправка текущих онлайн-игроков при старте плагина
|
||
scheduler.scheduleAtFixedRate(this::sendOnlinePlayersUpdate, 60, 60, TimeUnit.SECONDS);
|
||
|
||
marketplaceUrl = getConfig().getString("api-base", "http://localhost:8000") + "/api/marketplace";
|
||
scheduler.scheduleAtFixedRate(this::checkMarketplaceOperations, 3, 3, TimeUnit.SECONDS);
|
||
|
||
getLogger().info("PopaPlugin has been enabled!");
|
||
getLogger().info("API URL: " + apiUrl);
|
||
getLogger().info("Commands URL: " + commandsUrl);
|
||
getLogger().info("Inventory Requests URL: " + inventoryRequestsUrl);
|
||
getLogger().info("Server IP: " + serverIp);
|
||
}
|
||
|
||
@Override
|
||
public void onDisable() {
|
||
// Отправка финального списка игроков при выключении
|
||
sendOnlinePlayersUpdate();
|
||
|
||
// Останавливаем планировщик
|
||
if (scheduler != null) {
|
||
scheduler.shutdown();
|
||
try {
|
||
if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
|
||
scheduler.shutdownNow();
|
||
}
|
||
} catch (InterruptedException e) {
|
||
scheduler.shutdownNow();
|
||
}
|
||
}
|
||
|
||
getLogger().info("PopaPlugin has been disabled!");
|
||
}
|
||
|
||
private String getServerIp() {
|
||
try {
|
||
return InetAddress.getLocalHost().getHostAddress();
|
||
} catch (Exception e) {
|
||
return "unknown";
|
||
}
|
||
}
|
||
|
||
@EventHandler
|
||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||
Player player = event.getPlayer();
|
||
UUID playerId = player.getUniqueId();
|
||
String playerName = player.getName();
|
||
|
||
playerLoginTimes.put(playerId, System.currentTimeMillis());
|
||
playerNames.put(playerId, playerName);
|
||
|
||
String joinPayload = String.format(
|
||
"{\"event_type\":\"player_join\",\"player_id\":\"%s\",\"player_name\":\"%s\",\"server_ip\":\"%s\"}",
|
||
playerId, playerName, serverIp
|
||
);
|
||
sendEventToBackend(joinPayload);
|
||
sendOnlinePlayersUpdate();
|
||
}
|
||
|
||
@EventHandler
|
||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||
Player player = event.getPlayer();
|
||
UUID playerId = player.getUniqueId();
|
||
String playerName = player.getName();
|
||
|
||
if (playerLoginTimes.containsKey(playerId)) {
|
||
long sessionTime = (System.currentTimeMillis() - playerLoginTimes.get(playerId)) / 1000;
|
||
String sessionPayload = String.format(
|
||
"{\"event_type\":\"player_session\",\"player_id\":\"%s\",\"player_name\":\"%s\",\"duration\":%d,\"server_ip\":\"%s\"}",
|
||
playerId, playerName, sessionTime, serverIp
|
||
);
|
||
sendEventToBackend(sessionPayload);
|
||
}
|
||
|
||
String quitPayload = String.format(
|
||
"{\"event_type\":\"player_quit\",\"player_id\":\"%s\",\"player_name\":\"%s\",\"server_ip\":\"%s\"}",
|
||
playerId, playerName, serverIp
|
||
);
|
||
sendEventToBackend(quitPayload);
|
||
|
||
playerLoginTimes.remove(playerId);
|
||
playerNames.remove(playerId);
|
||
sendOnlinePlayersUpdate();
|
||
}
|
||
|
||
private void sendOnlinePlayersUpdate() {
|
||
StringBuilder playersJson = new StringBuilder("[");
|
||
boolean first = true;
|
||
|
||
for (Map.Entry<UUID, Long> entry : playerLoginTimes.entrySet()) {
|
||
UUID playerId = entry.getKey();
|
||
String playerName = playerNames.get(playerId);
|
||
long onlineTime = (System.currentTimeMillis() - entry.getValue()) / 1000;
|
||
|
||
if (!first) playersJson.append(",");
|
||
first = false;
|
||
|
||
playersJson.append(String.format(
|
||
"{\"player_id\":\"%s\",\"player_name\":\"%s\",\"online_time\":%d}",
|
||
playerId, playerName, onlineTime
|
||
));
|
||
}
|
||
|
||
playersJson.append("]");
|
||
|
||
String payload = String.format(
|
||
"{\"event_type\":\"online_players_update\",\"players\":%s,\"timestamp\":%d,\"server_ip\":\"%s\"}",
|
||
playersJson.toString(), System.currentTimeMillis(), serverIp
|
||
);
|
||
|
||
sendEventToBackend(payload);
|
||
}
|
||
|
||
private void sendEventToBackend(String jsonPayload) {
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(apiUrl))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.header("Content-Type", "application/json")
|
||
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
|
||
.build();
|
||
|
||
try {
|
||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
getLogger().info("Event sent to backend. Response: " + response.statusCode());
|
||
} catch (IOException | InterruptedException e) {
|
||
getLogger().warning("Failed to send event to backend: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
private void checkAndExecuteCommands() {
|
||
if (!getServer().isPrimaryThread()) {
|
||
Bukkit.getScheduler().runTask(this, this::checkAndExecuteCommands);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(commandsUrl + "?server_ip=" + serverIp))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.GET()
|
||
.build();
|
||
|
||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
|
||
if (response.statusCode() == 200) {
|
||
JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
|
||
JsonArray commands = json.getAsJsonArray("commands");
|
||
|
||
for (JsonElement cmd : commands) {
|
||
JsonObject command = cmd.getAsJsonObject();
|
||
String cmdText = command.get("command").getAsString();
|
||
boolean requireOnline = command.get("require_online_player").getAsBoolean();
|
||
|
||
// Получаем оба типа сообщений
|
||
String targetMessage = null;
|
||
String globalMessage = null;
|
||
|
||
if (command.has("target_message") && !command.get("target_message").isJsonNull()) {
|
||
targetMessage = command.get("target_message").getAsString();
|
||
}
|
||
|
||
if (command.has("global_message") && !command.get("global_message").isJsonNull()) {
|
||
globalMessage = command.get("global_message").getAsString();
|
||
}
|
||
|
||
if (!requireOnline || !Bukkit.getOnlinePlayers().isEmpty()) {
|
||
if (cmdText.startsWith("/")) {
|
||
cmdText = cmdText.substring(1);
|
||
}
|
||
|
||
// Выполняем команду
|
||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmdText);
|
||
getLogger().info("Выполнена команда: " + cmdText);
|
||
|
||
// Если есть сообщения, отображаем их
|
||
if ((targetMessage != null && !targetMessage.isEmpty()) ||
|
||
(globalMessage != null && !globalMessage.isEmpty())) {
|
||
|
||
// Извлекаем имя целевого игрока из команды
|
||
String targetPlayerName = extractTargetPlayerName(cmdText);
|
||
Player targetPlayer = null;
|
||
|
||
if (targetPlayerName != null) {
|
||
targetPlayer = Bukkit.getPlayer(targetPlayerName);
|
||
}
|
||
|
||
// Отправляем персональное сообщение цели
|
||
if (targetPlayer != null && targetMessage != null && !targetMessage.isEmpty()) {
|
||
targetPlayer.sendMessage("§c" + targetMessage);
|
||
}
|
||
|
||
// Отправляем сообщение всем остальным
|
||
if (globalMessage != null && !globalMessage.isEmpty()) {
|
||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||
// Если это не целевой игрок, отправляем сообщение
|
||
if (targetPlayer == null || !player.equals(targetPlayer)) {
|
||
player.sendMessage("§7" + globalMessage);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при выполнении команд: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Проверяет наличие запросов инвентаря на бэкенде
|
||
*/
|
||
private void checkInventoryRequests() {
|
||
if (!getServer().isPrimaryThread()) {
|
||
Bukkit.getScheduler().runTask(this, this::checkInventoryRequests);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Выводим полный URL для отладки
|
||
String requestUrl = inventoryRequestsUrl + "?server_ip=" + serverIp;
|
||
getLogger().info("Запрашиваем инвентарь по URL: " + requestUrl);
|
||
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(requestUrl))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.GET()
|
||
.build();
|
||
|
||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
|
||
// Выводим код ответа и тело для отладки
|
||
getLogger().info("Получен ответ от API: " + response.statusCode());
|
||
getLogger().info("Тело ответа: " + response.body());
|
||
|
||
if (response.statusCode() == 200) {
|
||
JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
|
||
|
||
// Проверяем статус
|
||
if (json.has("status") && "success".equals(json.get("status").getAsString())) {
|
||
if (json.has("inventory_requests")) {
|
||
JsonArray requests = json.getAsJsonArray("inventory_requests");
|
||
getLogger().info("Найдено запросов инвентаря: " + requests.size());
|
||
|
||
for (JsonElement req : requests) {
|
||
JsonObject request_obj = req.getAsJsonObject();
|
||
String requestId = request_obj.get("id").getAsString();
|
||
String playerName = request_obj.get("player_name").getAsString();
|
||
|
||
getLogger().info("Обработка запроса инвентаря: " + requestId + " для игрока " + playerName);
|
||
|
||
// Находим игрока и отправляем его инвентарь
|
||
Player player = Bukkit.getPlayer(playerName);
|
||
|
||
if (player != null && player.isOnline()) {
|
||
getLogger().info("Игрок " + playerName + " найден, отправляем инвентарь");
|
||
sendPlayerInventory(player, requestId);
|
||
} else {
|
||
getLogger().info("Игрок " + playerName + " не найден или не в сети");
|
||
sendEmptyInventory(playerName, requestId);
|
||
}
|
||
}
|
||
} else {
|
||
getLogger().info("В ответе нет поля inventory_requests");
|
||
}
|
||
} else {
|
||
getLogger().info("Статус ответа не success: " + json.toString());
|
||
}
|
||
} else {
|
||
getLogger().warning("Некорректный статус ответа: " + response.statusCode());
|
||
}
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при проверке запросов инвентаря: " + e.getMessage());
|
||
if (e.getCause() != null) {
|
||
getLogger().warning("Причина: " + e.getCause().getMessage());
|
||
}
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Отправляет данные о содержимом инвентаря игрока на бэкенд
|
||
*/
|
||
private void sendPlayerInventory(Player player, String requestId) {
|
||
// Формируем JSON с содержимым инвентаря
|
||
PlayerInventory inv = player.getInventory();
|
||
JsonArray inventoryArray = new JsonArray();
|
||
|
||
// Добавляем основные слоты (0-35)
|
||
for (int i = 0; i < 36; i++) {
|
||
ItemStack item = inv.getItem(i);
|
||
inventoryArray.add(itemStackToJson(item, i));
|
||
}
|
||
|
||
// Добавляем слот шлема (39)
|
||
inventoryArray.add(itemStackToJson(inv.getHelmet(), 39));
|
||
|
||
// Добавляем слот нагрудника (38)
|
||
inventoryArray.add(itemStackToJson(inv.getChestplate(), 38));
|
||
|
||
// Добавляем слот поножей (37)
|
||
inventoryArray.add(itemStackToJson(inv.getLeggings(), 37));
|
||
|
||
// Добавляем слот ботинок (36)
|
||
inventoryArray.add(itemStackToJson(inv.getBoots(), 36));
|
||
|
||
// Добавляем слот дополнительной руки (40) если это доступно
|
||
inventoryArray.add(itemStackToJson(inv.getItemInOffHand(), 40));
|
||
|
||
// Формируем объект ответа
|
||
JsonObject responseJson = new JsonObject();
|
||
responseJson.addProperty("request_id", requestId);
|
||
responseJson.add("inventory", inventoryArray);
|
||
responseJson.addProperty("player_name", player.getName());
|
||
responseJson.addProperty("player_id", player.getUniqueId().toString());
|
||
responseJson.addProperty("server_ip", serverIp);
|
||
|
||
// Отправляем данные на бэкенд
|
||
sendInventoryToBackend(responseJson.toString());
|
||
}
|
||
|
||
/**
|
||
* Преобразует ItemStack в JsonObject
|
||
*/
|
||
private JsonObject itemStackToJson(ItemStack item, int slot) {
|
||
JsonObject itemJson = new JsonObject();
|
||
itemJson.addProperty("slot", slot);
|
||
|
||
if (item == null || item.getType() == Material.AIR) {
|
||
itemJson.addProperty("material", "AIR");
|
||
itemJson.addProperty("amount", 0);
|
||
} else {
|
||
itemJson.addProperty("material", item.getType().toString());
|
||
itemJson.addProperty("amount", item.getAmount());
|
||
|
||
if (item.hasItemMeta()) {
|
||
if (item.getItemMeta().hasDisplayName()) {
|
||
itemJson.addProperty("display_name", item.getItemMeta().getDisplayName());
|
||
}
|
||
|
||
if (item.getItemMeta().hasLore()) {
|
||
JsonArray loreArray = new JsonArray();
|
||
for (String line : item.getItemMeta().getLore()) {
|
||
loreArray.add(line);
|
||
}
|
||
itemJson.add("lore", loreArray);
|
||
}
|
||
|
||
if (item.getItemMeta().hasEnchants()) {
|
||
JsonObject enchants = new JsonObject();
|
||
item.getItemMeta().getEnchants().forEach((enchantment, level) -> {
|
||
enchants.addProperty(enchantment.getKey().toString(), level);
|
||
});
|
||
itemJson.add("enchants", enchants);
|
||
}
|
||
}
|
||
}
|
||
|
||
return itemJson;
|
||
}
|
||
|
||
/**
|
||
* Отправляет информацию о пустом инвентаре для оффлайн-игрока
|
||
*/
|
||
private void sendEmptyInventory(String playerName, String requestId) {
|
||
JsonObject responseJson = new JsonObject();
|
||
responseJson.addProperty("request_id", requestId);
|
||
responseJson.add("inventory", new JsonArray());
|
||
responseJson.addProperty("player_name", playerName);
|
||
responseJson.addProperty("server_ip", serverIp);
|
||
responseJson.addProperty("status", "player_offline");
|
||
|
||
sendInventoryToBackend(responseJson.toString());
|
||
}
|
||
|
||
/**
|
||
* Отправляет данные инвентаря на бэкенд
|
||
*/
|
||
private void sendInventoryToBackend(String jsonPayload) {
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(getConfig().getString("api-base", "http://localhost:8000") + "/api/server/inventory/submit"))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.header("Content-Type", "application/json")
|
||
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
|
||
.build();
|
||
|
||
try {
|
||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
getLogger().info("Inventory data sent to backend. Response: " + response.statusCode());
|
||
} catch (IOException | InterruptedException e) {
|
||
getLogger().warning("Failed to send inventory data to backend: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Проверяет запросы на операции с торговой площадкой
|
||
*/
|
||
private void checkMarketplaceOperations() {
|
||
if (!getServer().isPrimaryThread()) {
|
||
Bukkit.getScheduler().runTask(this, this::checkMarketplaceOperations);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(marketplaceUrl + "/operations?server_ip=" + serverIp))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.GET()
|
||
.build();
|
||
|
||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
|
||
if (response.statusCode() == 200) {
|
||
JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
|
||
|
||
if (json.has("operations") && json.get("operations").isJsonArray()) {
|
||
JsonArray operations = json.getAsJsonArray("operations");
|
||
|
||
for (JsonElement op : operations) {
|
||
JsonObject operation = op.getAsJsonObject();
|
||
String type = operation.get("type").getAsString();
|
||
String opId = operation.get("id").getAsString();
|
||
|
||
if ("sell".equals(type)) {
|
||
handleSellOperation(operation);
|
||
} else if ("buy".equals(type)) {
|
||
handleBuyOperation(operation);
|
||
}
|
||
|
||
// Подтверждаем выполнение операции
|
||
confirmOperation(opId);
|
||
}
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при проверке операций торговой площадки: " + e.getMessage());
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обрабатывает операцию продажи предмета
|
||
*/
|
||
private void handleSellOperation(JsonObject operation) {
|
||
String playerName = operation.get("player_name").getAsString();
|
||
int slotIndex = operation.get("slot_index").getAsInt();
|
||
|
||
Player player = Bukkit.getPlayer(playerName);
|
||
if (player == null || !player.isOnline()) {
|
||
sendOperationError(operation.get("id").getAsString(), "Игрок не в сети");
|
||
return;
|
||
}
|
||
|
||
PlayerInventory inv = player.getInventory();
|
||
ItemStack item = null;
|
||
|
||
// Получаем предмет из нужного слота
|
||
if (slotIndex >= 0 && slotIndex <= 35) {
|
||
item = inv.getItem(slotIndex);
|
||
} else if (slotIndex == 36) {
|
||
item = inv.getBoots();
|
||
} else if (slotIndex == 37) {
|
||
item = inv.getLeggings();
|
||
} else if (slotIndex == 38) {
|
||
item = inv.getChestplate();
|
||
} else if (slotIndex == 39) {
|
||
item = inv.getHelmet();
|
||
} else if (slotIndex == 40) {
|
||
item = inv.getItemInOffHand();
|
||
}
|
||
|
||
if (item == null || item.getType() == Material.AIR) {
|
||
sendOperationError(operation.get("id").getAsString(), "Предмет не найден в указанном слоте");
|
||
return;
|
||
}
|
||
|
||
// Создаем полную копию предмета с метаданными для отправки на сервер
|
||
JsonObject itemData = itemStackToDetailedJson(item, slotIndex);
|
||
|
||
// Очищаем слот
|
||
if (slotIndex >= 0 && slotIndex <= 35) {
|
||
inv.setItem(slotIndex, null);
|
||
} else if (slotIndex == 36) {
|
||
inv.setBoots(null);
|
||
} else if (slotIndex == 37) {
|
||
inv.setLeggings(null);
|
||
} else if (slotIndex == 38) {
|
||
inv.setChestplate(null);
|
||
} else if (slotIndex == 39) {
|
||
inv.setHelmet(null);
|
||
} else if (slotIndex == 40) {
|
||
inv.setItemInOffHand(null);
|
||
}
|
||
|
||
// Отправляем сообщение игроку
|
||
int price = operation.get("price").getAsInt();
|
||
player.sendMessage("§aВы выставили предмет на продажу за " + price + " монет");
|
||
|
||
// Отправляем данные о предмете на сервер
|
||
sendItemDetails(operation.get("id").getAsString(), itemData);
|
||
}
|
||
|
||
/**
|
||
* Обрабатывает операцию покупки предмета
|
||
*/
|
||
private void handleBuyOperation(JsonObject operation) {
|
||
String playerName = operation.get("player_name").getAsString();
|
||
JsonObject itemData = operation.getAsJsonObject("item_data");
|
||
|
||
Player player = Bukkit.getPlayer(playerName);
|
||
if (player == null || !player.isOnline()) {
|
||
sendOperationError(operation.get("id").getAsString(), "Игрок не в сети");
|
||
return;
|
||
}
|
||
|
||
// Создаем предмет из данных
|
||
ItemStack item = jsonToItemStack(itemData);
|
||
if (item == null) {
|
||
sendOperationError(operation.get("id").getAsString(), "Не удалось создать предмет");
|
||
return;
|
||
}
|
||
|
||
// Добавляем предмет в инвентарь
|
||
HashMap<Integer, ItemStack> leftItems = player.getInventory().addItem(item);
|
||
|
||
// Если предмет не поместился полностью, бросаем остаток на землю
|
||
if (!leftItems.isEmpty()) {
|
||
for (ItemStack leftItem : leftItems.values()) {
|
||
player.getWorld().dropItem(player.getLocation(), leftItem);
|
||
}
|
||
}
|
||
|
||
// Отправляем сообщение игроку
|
||
int price = operation.get("price").getAsInt();
|
||
player.sendMessage("§aВы купили предмет за " + price + " монет");
|
||
}
|
||
|
||
/**
|
||
* Создает ItemStack из JSON данных
|
||
*/
|
||
private ItemStack jsonToItemStack(JsonObject itemData) {
|
||
try {
|
||
String materialName = itemData.get("material").getAsString();
|
||
Material material = Material.valueOf(materialName);
|
||
int amount = itemData.get("amount").getAsInt();
|
||
|
||
ItemStack item = new ItemStack(material, amount);
|
||
|
||
// Если есть мета-данные
|
||
if (itemData.has("meta") && !itemData.get("meta").isJsonNull()) {
|
||
JsonObject meta = itemData.getAsJsonObject("meta");
|
||
org.bukkit.inventory.meta.ItemMeta itemMeta = item.getItemMeta();
|
||
|
||
// Устанавливаем отображаемое имя
|
||
if (meta.has("display_name")) {
|
||
itemMeta.setDisplayName(meta.get("display_name").getAsString());
|
||
}
|
||
|
||
// Устанавливаем lore
|
||
if (meta.has("lore") && meta.get("lore").isJsonArray()) {
|
||
JsonArray loreArray = meta.getAsJsonArray("lore");
|
||
java.util.List<String> lore = new java.util.ArrayList<>();
|
||
|
||
for (JsonElement line : loreArray) {
|
||
lore.add(line.getAsString());
|
||
}
|
||
|
||
itemMeta.setLore(lore);
|
||
}
|
||
|
||
// Устанавливаем зачарования
|
||
if (meta.has("enchants") && meta.get("enchants").isJsonObject()) {
|
||
JsonObject enchants = meta.getAsJsonObject("enchants");
|
||
|
||
for (Map.Entry<String, JsonElement> entry : enchants.entrySet()) {
|
||
org.bukkit.enchantments.Enchantment enchantment =
|
||
org.bukkit.enchantments.Enchantment.getByKey(org.bukkit.NamespacedKey.minecraft(entry.getKey()));
|
||
|
||
if (enchantment != null) {
|
||
itemMeta.addEnchant(enchantment, entry.getValue().getAsInt(), true);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Устанавливаем прочность
|
||
if (meta.has("durability") && itemMeta instanceof org.bukkit.inventory.meta.Damageable) {
|
||
org.bukkit.inventory.meta.Damageable damageable = (org.bukkit.inventory.meta.Damageable) itemMeta;
|
||
damageable.setDamage(meta.get("durability").getAsInt());
|
||
}
|
||
|
||
item.setItemMeta(itemMeta);
|
||
}
|
||
|
||
return item;
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при создании предмета из JSON: " + e.getMessage());
|
||
e.printStackTrace();
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Преобразует ItemStack в детальный JsonObject со всеми мета-данными
|
||
*/
|
||
private JsonObject itemStackToDetailedJson(ItemStack item, int slot) {
|
||
JsonObject itemJson = new JsonObject();
|
||
itemJson.addProperty("slot", slot);
|
||
|
||
if (item == null || item.getType() == Material.AIR) {
|
||
itemJson.addProperty("material", "AIR");
|
||
itemJson.addProperty("amount", 0);
|
||
return itemJson;
|
||
}
|
||
|
||
itemJson.addProperty("material", item.getType().toString());
|
||
itemJson.addProperty("amount", item.getAmount());
|
||
|
||
// Добавляем мета-данные
|
||
if (item.hasItemMeta()) {
|
||
JsonObject metaJson = new JsonObject();
|
||
|
||
if (item.getItemMeta().hasDisplayName()) {
|
||
metaJson.addProperty("display_name", item.getItemMeta().getDisplayName());
|
||
}
|
||
|
||
if (item.getItemMeta().hasLore()) {
|
||
JsonArray loreArray = new JsonArray();
|
||
for (String line : item.getItemMeta().getLore()) {
|
||
loreArray.add(line);
|
||
}
|
||
metaJson.add("lore", loreArray);
|
||
}
|
||
|
||
if (item.getItemMeta().hasEnchants()) {
|
||
JsonObject enchants = new JsonObject();
|
||
item.getItemMeta().getEnchants().forEach((enchantment, level) -> {
|
||
enchants.addProperty(enchantment.getKey().getKey(), level);
|
||
});
|
||
metaJson.add("enchants", enchants);
|
||
}
|
||
|
||
// Сохраняем данные о прочности
|
||
if (item.getItemMeta() instanceof org.bukkit.inventory.meta.Damageable) {
|
||
org.bukkit.inventory.meta.Damageable damageable =
|
||
(org.bukkit.inventory.meta.Damageable) item.getItemMeta();
|
||
metaJson.addProperty("durability", damageable.getDamage());
|
||
}
|
||
|
||
itemJson.add("meta", metaJson);
|
||
}
|
||
|
||
return itemJson;
|
||
}
|
||
|
||
/**
|
||
* Отправляет детальную информацию о предмете на сервер
|
||
*/
|
||
private void sendItemDetails(String operationId, JsonObject itemData) {
|
||
JsonObject payload = new JsonObject();
|
||
payload.addProperty("operation_id", operationId);
|
||
payload.add("item_data", itemData);
|
||
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(marketplaceUrl + "/items/details"))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.header("Content-Type", "application/json")
|
||
.POST(HttpRequest.BodyPublishers.ofString(payload.toString()))
|
||
.build();
|
||
|
||
try {
|
||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при отправке данных предмета: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Отправляет ошибку операции
|
||
*/
|
||
private void sendOperationError(String operationId, String error) {
|
||
JsonObject payload = new JsonObject();
|
||
payload.addProperty("operation_id", operationId);
|
||
payload.addProperty("status", "error");
|
||
payload.addProperty("error", error);
|
||
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(marketplaceUrl + "/operations/confirm"))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.header("Content-Type", "application/json")
|
||
.POST(HttpRequest.BodyPublishers.ofString(payload.toString()))
|
||
.build();
|
||
|
||
try {
|
||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при отправке ошибки операции: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Подтверждает выполнение операции
|
||
*/
|
||
private void confirmOperation(String operationId) {
|
||
JsonObject payload = new JsonObject();
|
||
payload.addProperty("operation_id", operationId);
|
||
payload.addProperty("status", "success");
|
||
|
||
HttpRequest request = HttpRequest.newBuilder()
|
||
.uri(URI.create(marketplaceUrl + "/operations/confirm"))
|
||
.version(HttpClient.Version.HTTP_1_1)
|
||
.header("Content-Type", "application/json")
|
||
.POST(HttpRequest.BodyPublishers.ofString(payload.toString()))
|
||
.build();
|
||
|
||
try {
|
||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||
} catch (Exception e) {
|
||
getLogger().warning("Ошибка при подтверждении операции: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Пытается извлечь имя целевого игрока из команды
|
||
*/
|
||
private String extractTargetPlayerName(String command) {
|
||
// Ищем по шаблону в команде имя игрока
|
||
// Пример: в команде "execute at PlayerName run summon lightning_bolt ~ ~ ~"
|
||
// нужно извлечь PlayerName
|
||
|
||
String[] parts = command.split(" ");
|
||
for (int i = 0; i < parts.length; i++) {
|
||
if (i > 0 && parts[i-1].equalsIgnoreCase("at")) {
|
||
// После слова "at" обычно идет имя игрока
|
||
String potentialName = parts[i];
|
||
// Проверяем, существует ли такой игрок
|
||
if (Bukkit.getPlayer(potentialName) != null) {
|
||
return potentialName;
|
||
}
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|