> For the complete documentation index, see [llms.txt](https://kast1ent.gitbook.io/kast1ent-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kast1ent.gitbook.io/kast1ent-docs/api-kastfight/api.md).

# API

## API для разработчиков

KastFight теперь даёт другим плагинам публичный Java API через Bukkit `ServicesManager`. Основной класс: `me.kastfight.kastfight.api.KastFightApi`.

Важно: API нужно брать после загрузки KastFight. В `plugin.yml` стороннего плагина лучше указать:

```yaml
depend:
  - KastFight
```

Или, если интеграция необязательная:

```yaml
softdepend:
  - KastFight
```

### Получить API

```java
import me.kastfight.kastfight.api.KastFightApi;
import org.bukkit.Bukkit;
import org.bukkit.plugin.RegisteredServiceProvider;

RegisteredServiceProvider<KastFightApi> rsp =
        Bukkit.getServicesManager().getRegistration(KastFightApi.class);

if (rsp == null) {
    return; // KastFight не загружен или API недоступен
}

KastFightApi api = rsp.getProvider();
```

Если ваш код уже работает внутри KastFight, можно взять напрямую:

```java
KastFightApi api = kastFightPlugin.getApi();
```

### Общие методы

| Метод                          | Что делает                                          |
| ------------------------------ | --------------------------------------------------- |
| `plugin()`                     | вернуть основной `KastFightPlugin`                  |
| `version()`                    | версия KastFight                                    |
| `reload()`                     | выполнить полный reload KastFight                   |
| `resolvePlayer(UUID)`          | найти онлайн-игрока или управляемого бота KastFight |
| `findPlayerExactOrBot(String)` | найти игрока или бота по точному нику               |
| `isManagedBot(UUID)`           | проверить, что UUID принадлежит боту KastFight      |

### Очереди

```java
api.joinQueue(player, "boxing");
api.joinQueue(player, KitMode.RATING, "boxing");
api.joinPremiumQueue(player, KitMode.DEFAULT, "boxing");
api.leaveQueue(player);
```

| Метод                                       | Что делает                          |
| ------------------------------------------- | ----------------------------------- |
| `joinQueue(Player, String)`                 | войти в обычную очередь default     |
| `joinQueue(Player, KitMode, String)`        | войти в очередь выбранного режима   |
| `joinPremiumQueue(Player, KitMode, String)` | войти в premium-очередь             |
| `leaveQueue(Player)`                        | выйти из очереди                    |
| `leaveQueueSilent(UUID)`                    | убрать из очереди без сообщений     |
| `isQueued(UUID)`                            | игрок сейчас в очереди              |
| `getQueuedKit(UUID)`                        | id кита в очереди                   |
| `getQueuedMode(UUID)`                       | режим очереди                       |
| `getTotalQueued()`                          | всего игроков в очередях            |
| `getQueuedForKit(KitMode, String)`          | игроков в очереди кита              |
| `getQueuedForKit(KitMode, String, boolean)` | игроков в обычной/premium очереди   |
| `getSearchTimeFormatted(UUID)`              | время поиска в формате `mm:ss`      |
| `isRatingUnlocked(UUID)`                    | открыт ли рейтинг                   |
| `getRatingUnlockRemainingMatches(UUID)`     | сколько матчей осталось до рейтинга |
| `getRatingUnlockRemainingWins(UUID)`        | сколько побед осталось до рейтинга  |

Результат входа:

```java
QueueManager.JoinResult result = api.joinQueue(player, KitMode.RATING, "boxing");
if (result == QueueManager.JoinResult.RATING_LOCKED) {
    player.sendMessage("Рейтинг пока закрыт.");
}
```

### Матчи и дуэли

```java
api.startDuel(player1, player2, KitMode.DEFAULT, "boxing");

if (api.isInMatch(player.getUniqueId())) {
    Match match = api.getMatch(player.getUniqueId());
    UUID opponent = api.getOpponent(player.getUniqueId());
}
```

| Метод                                        | Что делает                               |
| -------------------------------------------- | ---------------------------------------- |
| `startDuel(Player, Player, KitMode, String)` | начать дуэль на свободной арене          |
| `startDuel(Player, Player, Kit, Arena)`      | начать дуэль с конкретным китом и ареной |
| `isInMatch(UUID)`                            | игрок находится в матче                  |
| `getMatch(UUID)`                             | получить `Match` игрока                  |
| `getOpponent(UUID)`                          | UUID противника                          |
| `getActiveMatchCount()`                      | количество активных матчей               |
| `getPlayersInFight(KitMode, String)`         | игроков в боях по киту                   |
| `findMatchAt(Location)`                      | найти матч по локации внутри арены       |

Дуэльные приглашения:

```java
api.sendDuelInvite(inviter, target, "boxing");
api.acceptDuelInvite(target, inviter.getName());
api.declineDuelInvite(target, inviter.getName());
```

| Метод                                    | Что делает                   |
| ---------------------------------------- | ---------------------------- |
| `sendDuelInvite(Player, Player, String)` | отправить вызов на дуэль     |
| `acceptDuelInvite(Player, String)`       | принять вызов                |
| `declineDuelInvite(Player, String)`      | отклонить вызов              |
| `hasPendingDuelInvite(UUID)`             | есть ожидающий вызов         |
| `getPendingDuelInvite(UUID)`             | получить объект `DuelInvite` |
| `getDuelInviteExpireMillis()`            | время жизни приглашения      |

### FFA

```java
api.joinFfa(player, "boxing");
api.leaveFfa(player);
```

| Метод                                         | Что делает                 |
| --------------------------------------------- | -------------------------- |
| `joinFfa(Player, String)`                     | войти на FFA-арену по киту |
| `leaveFfa(Player)`                            | выйти из FFA               |
| `isInFfa(UUID)`                               | игрок в FFA                |
| `getFfaSession(UUID)`                         | получить `FfaSession`      |
| `getPlayersInFfaKit(String)`                  | игроков в FFA по киту      |
| `isInFfaCombat(UUID)`                         | игрок в combat-tag         |
| `getFfaCombatRemainingSeconds(UUID)`          | остаток combat-tag         |
| `isFfaSpawnProtected(UUID)`                   | есть spawn-protection      |
| `getFfaSpawnProtectionRemainingSeconds(UUID)` | остаток защиты             |
| `getActiveFfaOpponent(UUID)`                  | активный противник в FFA   |

Пример:

```java
if (api.isInFfaCombat(player.getUniqueId())) {
    int left = api.getFfaCombatRemainingSeconds(player.getUniqueId());
    player.sendMessage("Нельзя телепортироваться ещё " + left + " сек.");
}
```

### Киты

```java
Kit kit = api.getKit(KitMode.DEFAULT, "boxing");
List<String> ids = api.listKitIds(KitMode.RATING);
```

| Метод                                | Что делает                      |
| ------------------------------------ | ------------------------------- |
| `kitExists(KitMode, String)`         | проверить наличие кита          |
| `getKit(KitMode, String)`            | загрузить кит                   |
| `listKitIds(KitMode)`                | список id китов                 |
| `createKit(KitMode, String, String)` | создать кит                     |
| `saveKit(Kit)`                       | сохранить изменённый кит        |
| `deleteKit(KitMode, String)`         | удалить кит                     |
| `normalizeKitId(String)`             | привести id к формату KastFight |

Пример изменения имени:

```java
Kit kit = api.getKit(KitMode.DEFAULT, "boxing");
if (kit != null) {
    kit.setDisplayName("Boxing Pro");
    api.saveKit(kit);
}
```

### Арены

```java
Arena arena = api.createArena(ArenaType.DUEL, "arena2", "Arena 2");
api.setDuelArenaPos1("arena2", player.getLocation());
```

| Метод                                          | Что делает                |
| ---------------------------------------------- | ------------------------- |
| `listArenas()`                                 | все арены                 |
| `listArenas(ArenaType)`                        | арены нужного типа        |
| `getArena(String)`                             | найти арену по id         |
| `getArena(ArenaType, String)`                  | найти арену по типу и id  |
| `createArena(ArenaType, String, String)`       | создать арену             |
| `deleteArena(ArenaType, String)`               | удалить арену             |
| `setDuelArenaPos1(String, Location)`           | spawn первого игрока      |
| `setDuelArenaPos2(String, Location)`           | spawn второго игрока      |
| `setArenaBorder1(ArenaType, String, Location)` | первая граница            |
| `setArenaBorder2(ArenaType, String, Location)` | вторая граница            |
| `setFfaSpawn(String, int, Location)`           | FFA-spawn                 |
| `setFfaArenaKit(String, String)`               | привязать FFA-кит к арене |

### Рейтинг и статистика

```java
int elo = api.getElo(player.getUniqueId(), "boxing", 1000);
api.setElo(player.getUniqueId(), "boxing", elo + 25);
```

| Метод                             | Что делает                      |
| --------------------------------- | ------------------------------- |
| `getElo(UUID, String, int)`       | Elo игрока по киту              |
| `setElo(UUID, String, int)`       | выставить Elo по киту           |
| `getTotalElo(UUID)`               | общий Elo                       |
| `setTotalElo(UUID, int)`          | выставить общий Elo             |
| `getDuelMatches(UUID)`            | сыгранные дуэли                 |
| `getDuelWins(UUID)`               | победы в дуэлях                 |
| `recordDuelResult(UUID, boolean)` | записать результат дуэли        |
| `updateRatingTop()`               | пересчитать топы                |
| `getTopForKit(String, int)`       | место в топе по киту            |
| `getTopTotal(int)`                | место в общем топе              |
| `getRankForKit(String, UUID)`     | позиция игрока по киту          |
| `getTotalRank(UUID)`              | позиция игрока в общем рейтинге |

### Наблюдение

```java
api.startSpectate(viewer, target);
api.stopSpectate(viewer);
```

| Метод                           | Что делает              |
| ------------------------------- | ----------------------- |
| `startSpectate(Player, Player)` | начать наблюдение       |
| `stopSpectate(Player)`          | выйти из наблюдения     |
| `isSpectating(UUID)`            | игрок сейчас в spectate |

### Скорборды

```java
api.setScoreboardDisabledFor(player.getUniqueId(), true);
api.updateScoreboard(player);
```

| Метод                                     | Что делает                         |
| ----------------------------------------- | ---------------------------------- |
| `updateScoreboard(Player)`                | обновить скорборд игроку           |
| `areScoreboardsEnabled()`                 | включены ли скорборды глобально    |
| `isScoreboardDisabledFor(UUID)`           | выключен ли скорборд игроком       |
| `setScoreboardDisabledFor(UUID, boolean)` | включить/выключить скорборд игроку |

### Hub-предметы

```java
api.giveLobbyItems(player);
api.giveSearchingItems(player);
```

| Метод                          | Что делает                       |
| ------------------------------ | -------------------------------- |
| `giveLobbyItems(Player)`       | выдать предметы лобби            |
| `giveSearchingItems(Player)`   | выдать предметы поиска           |
| `isHubItem(ItemStack)`         | предмет принадлежит KastFight    |
| `getHubItemId(ItemStack)`      | id hub-предмета                  |
| `getHubItemContext(ItemStack)` | контекст `LOBBY` или `SEARCHING` |

### Редактор китов

```java
api.enterKitEditor(player, KitMode.DEFAULT, "boxing");
api.saveKitEditor(player);
api.leaveKitEditor(player);
```

| Метод                                     | Что делает                 |
| ----------------------------------------- | -------------------------- |
| `enterKitEditor(Player, KitMode, String)` | открыть редактор кита      |
| `saveKitEditor(Player)`                   | сохранить личную раскладку |
| `resetKitEditor(Player)`                  | сбросить личную раскладку  |
| `leaveKitEditor(Player)`                  | выйти из редактора         |
| `isEditingKit(UUID)`                      | игрок в редакторе          |

### Кулдауны предметов

```java
long left = api.getCooldownRemainingMillis(player.getUniqueId(), "pearl");
api.clearCooldowns(player.getUniqueId());
```

| Метод                                        | Что делает                    |
| -------------------------------------------- | ----------------------------- |
| `listCooldownRules()`                        | все правила кулдаунов         |
| `listCooldownRules(CooldownTarget)`          | правила по цели               |
| `getCooldownRule(CooldownTarget, String)`    | найти правило                 |
| `upsertCooldownRule(CooldownRule)`           | создать или обновить правило  |
| `removeCooldownRule(CooldownTarget, String)` | удалить правило               |
| `getCooldownRemainingMillis(UUID, String)`   | остаток кулдауна              |
| `clearCooldowns(UUID)`                       | очистить кулдауны игрока      |
| `clearAllCooldowns()`                        | очистить все runtime-кулдауны |

### События

События находятся в пакете:

```
me.kastfight.kastfight.api.event
```

| Событие                      | Когда вызывается                   |
| ---------------------------- | ---------------------------------- |
| `KastFightQueueJoinEvent`    | игрок успешно вошёл в очередь      |
| `KastFightQueueLeaveEvent`   | игрок успешно вышел из очереди     |
| `KastFightMatchStartEvent`   | создан и запущен матч              |
| `KastFightMatchEndEvent`     | матч завершился победой или ничьей |
| `KastFightFfaJoinEvent`      | игрок успешно вошёл в FFA          |
| `KastFightFfaLeaveEvent`     | игрок успешно вышел из FFA         |
| `KastFightFfaCombatTagEvent` | игроки получили FFA combat-tag     |

Пример listener:

```java
import me.kastfight.kastfight.api.event.KastFightMatchEndEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public final class MyListener implements Listener {

    @EventHandler
    public void onKastFightEnd(KastFightMatchEndEvent event) {
        if (event.isDraw()) {
            return;
        }

        event.getWinner().sendMessage("Победа через KastFight API!");
    }
}
```

### Полный пример команды

Команда отправляет игрока в рейтинговую очередь `boxing`, если рейтинг открыт:

```java
if (!api.isRatingUnlocked(player.getUniqueId())) {
    int left = api.getRatingUnlockRemainingMatches(player.getUniqueId());
    player.sendMessage("До рейтинга осталось матчей: " + left);
    return true;
}

QueueManager.JoinResult result = api.joinQueue(player, KitMode.RATING, "boxing");
switch (result) {
    case OK -> player.sendMessage("Вы вошли в рейтинговую очередь.");
    case KIT_NOT_FOUND -> player.sendMessage("Кит boxing не найден.");
    case ALREADY_IN_QUEUE -> player.sendMessage("Вы уже в очереди.");
    case IN_MATCH -> player.sendMessage("Вы уже в бою.");
    case RATING_LOCKED -> player.sendMessage("Рейтинг закрыт.");
}
```

### Важно

* Большинство методов нужно вызывать из основного Bukkit-потока.
* Id китов нормализуются в нижний регистр.
* Для `rating` нужны киты из `kits/Rating`.
* Для `ffa` нужны киты из `kits/Ffa`.
* `startDuel` использует свободную готовую duel-арену.
* События сейчас информационные: они сообщают о результате действия, но не отменяют его.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://kast1ent.gitbook.io/kast1ent-docs/api-kastfight/api.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
