all working

This commit is contained in:
2025-07-19 01:20:51 +05:00
commit f69b2c9c37
25 changed files with 2303 additions and 0 deletions

View File

@ -0,0 +1,489 @@
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 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);
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 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;
}
}