Verze pluginu: 1.2
Minecraft API: Paper 1.21.1
Jazyk: Kotlin 2.x · JVM 21
- Přehled projektu
- Architektura
- Struktura souborů
- Instalace a nasazení
- Konfigurace
- HTTP API
- In-game příkazy
- Hologramový systém
- Scoreboard klient
- Datové modely
- Soft-závislosti
- Sestavení projektu
- Testy
- Bezpečnost
- Životní cyklus pluginu
- Řešení problémů
SentryAPI je Minecraft Paper plugin určený pro server SentrySMP. Kombinuje dvě hlavní funkce:
- REST HTTP API — umožňuje externím službám (např. webovému rozhraní serveru nebo Discord botovi) komunikovat se serverem: spouštět příkazy, zjišťovat seznam hráčů, banlist a statistiky hráčů.
- Hologramový store leaderboard — zobrazuje žebříček hráčů podle jejich plateb v obchodě přímo ve světě jako hologram složený z neviditelných ArmorStand entit; data jsou načítána z veřejného API
sentrysmp.eu.
Plugin je napsán v jazyce Kotlin a využívá framework Ktor s enginem Netty jako embedded HTTP server.
┌─────────────────────────────────────────────────────────┐
│ Paper Server (hlavní vlákno JVM) │
│ │
│ CommandApiPlugin (JavaPlugin) │
│ ├── onEnable() │
│ │ ├── Načte config.yml │
│ │ ├── Vytvoří ScoreboardClient (HTTP klient + cache) │
│ │ ├── Zaregistruje HoloCommand executor │
│ │ ├── Nastartuje embedded Ktor/Netty server │
│ │ └── Obnoví přetrvávající hologramy │
│ └── onDisable() │
│ ├── Odstraní hologramy │
│ └── Zastaví HTTP server │
│ │
│ HoloCommand (CommandExecutor) │
│ ├── Zpracovává /sentrysmp holo add|remove │
│ ├── Načítá data přes ScoreboardClient (async vlákno) │
│ └── Spawnuje/obnovuje hologramy přes HologramRenderer │
│ │
│ HologramRenderer │
│ └── Vytváří/aktualizuje/odstraňuje ArmorStand entity │
│ │
│ ScoreboardClient │
│ └── HTTP volání na sentrysmp.eu/api s in-memory cache │
└───────────────┬─────────────────────────────────────────┘
│ HTTP (127.0.0.1:<port>)
┌───────────────▼─────────────────────────────────────────┐
│ Ktor / Netty embedded server │
│ Routes: │
│ ├── GET / (health check, bez auth) │
│ ├── GET /swagger (Swagger UI, bez auth) │
│ ├── POST /command (vykoná příkaz konzole) │
│ ├── GET /players (seznam online hráčů) │
│ ├── GET /banlist (seznam zabanovaných) │
│ └── GET /player/{name} (statistiky hráče) │
└─────────────────────────────────────────────────────────┘
- Thread safety: Veškerá volání Bukkit API (
dispatchCommand,getOnlinePlayers,getBannedPlayers, spawning entit) jsou vždy prováděna v hlavním vlákně serveru prostřednictvímBukkit.getScheduler().runTask(plugin, ...). Ktor handlery jsou suspending funkce, které přessuspendCancellableCoroutinečekají na výsledek z hlavního vlákna. - Lokální dostupnost: Server naslouchá výhradně na
127.0.0.1, nikoli na0.0.0.0. API tak není přístupné přímo z internetu. - Persistence hologramů: UUID všech ArmorStand entit patřících hologramům jsou ukládána do
holos.txt. Při startu pluginu jsou načteny a případné osiřelé entity (po pádu serveru) jsou odstraněny.
SentryAPI/
├── build.gradle.kts # Gradle build skript (závislosti, fatJar task)
├── settings.gradle.kts # Název projektu
├── gradle.properties # Verze Gradle
├── gradlew / gradlew.bat # Gradle Wrapper
├── README.md # Stručný přehled
├── DOCS.md # Tato dokumentace
└── src/
├── main/
│ ├── kotlin/com/sentrysmp/
│ │ ├── CommandApiPlugin.kt # Hlavní třída pluginu (JavaPlugin)
│ │ ├── Routes.kt # Definice HTTP endpointů a business logika
│ │ ├── Models.kt # Datové třídy (request/response modely)
│ │ ├── AppModule.kt # Test-friendly konfigurace Ktor aplikace
│ │ ├── HoloCommand.kt # Executor příkazu /sentrysmp holo
│ │ ├── HologramRenderer.kt # Spawn/update/remove ArmorStand hologramů
│ │ └── ScoreboardClient.kt # HTTP klient pro sentrysmp.eu API s cache
│ └── resources/
│ ├── plugin.yml # Paper plugin descriptor
│ ├── config.yml # Výchozí konfigurace
│ ├── logback.xml # Logování (Logback)
│ ├── documentation.yaml # OpenAPI spec (záloha)
│ └── openapi/
│ └── documentation.yaml # OpenAPI 3.0 spec (servírováno Swagger UI)
└── test/
└── kotlin/
└── ServerTest.kt # Základní integrační test
| Požadavek | Verze |
|---|---|
| Java (JDK) | 21+ |
| Paper Minecraft server | 1.21.1+ |
| LuckPerms (volitelné) | 5.4+ |
| PlaceholderAPI (volitelné) | libovolná kompatibilní |
-
Sestavte plugin (viz Sestavení projektu):
./gradlew fatJar
-
Zkopírujte JAR ze složky
build/libs/do složkyplugins/Paper serveru:plugins/SentryAPI-1.2-all.jar -
Spusťte server. Plugin se načte, vytvoří
plugins/SentryAPI/config.ymla nastartuje HTTP server. -
Upravte konfiguraci v
plugins/SentryAPI/config.yml(viz Konfigurace) a proveďte/reloadnebo restartujte server.
Konfigurační soubor se nachází v plugins/SentryAPI/config.yml. Výchozí hodnoty:
# TCP port, na kterém naslouchá HTTP server (pouze 127.0.0.1)
port: 8080
# API klíč — povinně změňte před nasazením!
api-key: "sentry_51Hk9ZQmX7pL3v9aB8cD2eF0gHiJkLmNoPqRsTuVwXyZ1234567890AbCdEfGhIj"
# Hologram settings
# Doba platnosti hologramu v sekundách (0 = neexpiruje)
hologram-ttl-seconds: 0
# Interval obnovování dat hologramu v sekundách
hologram-refresh-seconds: 5
# Scoreboard API settings
# Základní URL API pro data scoreboard
scoreboard-base-url: "https://www.sentrysmp.eu/api"
# TTL cache pro scoreboard klient v sekundách
scoreboard-cache-ttl: 60| Položka | Typ | Výchozí | Popis |
|---|---|---|---|
port |
int | 8080 |
Port HTTP serveru (pouze localhost) |
api-key |
string | (dlouhý řetězec) | Tajný klíč pro autentizaci; povinně změňte |
hologram-ttl-seconds |
long | 0 |
Jak dlouho hologram existuje (0 = navždy) |
hologram-refresh-seconds |
long | 5 |
Jak často se obnovují data hologramu |
scoreboard-base-url |
string | https://www.sentrysmp.eu/api |
Základní URL scoreboard API |
scoreboard-cache-ttl |
long | 60 |
TTL cache pro odpovědi scoreboard API |
Základní URL: http://127.0.0.1:<port>
Všechny endpointy kromě GET / a GET /swagger* vyžadují HTTP hlavičku:
X-API-Key: <hodnota api-key z config.yml>
Při chybějícím nebo nesprávném klíči server vrátí:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{"error": "Unauthorized"}Health-check endpoint. Nevyžaduje autentizaci.
Odpověď:
{"status": "ok"}HTTP kód: 200 OK
Vykoná příkaz na serveru jako konzolový sender.
Požadavek:
POST /command
X-API-Key: <klíč>
Content-Type: application/json
{"command": "say Hello World"}Odpověď:
{
"output": [],
"success": true
}| Pole | Typ | Popis |
|---|---|---|
command |
string | Příkaz bez úvodního lomítka (např. "op Steve") |
output |
string[] | Zachycený výstup příkazu (může být prázdný) |
success |
boolean | true pokud příkaz proběhl bez výjimky |
Poznámka: Pole
outputmůže být prázdné, protože zachycování výstupu z Bukkit konzole je závislé na implementaci pluginu, který příkaz obsluhuje. Konzolový výstup je zachytáván přes Log4j2 appender i přes delegovanýConsoleCommandSender, ale ne všechny pluginy posílají výstup stejnou cestou.
Vrátí seznam hráčů aktuálně přihlášených na serveru.
Požadavek:
GET /players
X-API-Key: <klíč>Odpověď:
{
"players": [
{"name": "Steve", "uuid": "069a79f4-44e9-4726-a5be-fca90e38aaf5"},
{"name": "Alex", "uuid": "8667ba71-b85a-4004-af54-457a9734eed7"}
]
}| Pole | Typ | Popis |
|---|---|---|
players |
PlayerInfo[] | Seznam online hráčů |
players[].name |
string | Herní jméno hráče |
players[].uuid |
string | UUID hráče (formát xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) |
Vrátí seznam zabanovaných hráčů (profilový ban, nikoli IP ban).
Požadavek:
GET /banlist
X-API-Key: <klíč>Odpověď:
{
"banned": [
{
"name": "Griefer99",
"uuid": "12345678-1234-1234-1234-123456789abc",
"reason": "Griefing and hacking"
}
]
}| Pole | Typ | Popis |
|---|---|---|
banned |
BanEntry[] | Seznam zabanovaných hráčů |
banned[].name |
string | Herní jméno hráče |
banned[].uuid |
string | UUID hráče |
banned[].reason |
string | null | Důvod banu (může být null) |
Vrátí statistiky hráče — počet coinů (PlayerPoints) a zůstatek peněz (Essentials Economy).
Požadavek:
GET /player/Steve
X-API-Key: <klíč>Odpověď (úspěch):
{
"player": "Steve",
"coins": 1500,
"money": 2345.75,
"error": null
}Odpověď (chyba):
{
"player": "Neexistující",
"coins": null,
"money": null,
"error": "Player not found"
}| Pole | Typ | Popis |
|---|---|---|
player |
string | Zadané jméno hráče |
coins |
long | null | Počet coinů z PlayerPoints (null pokud nelze zjistit) |
money |
double | null | Zůstatek z Essentials Economy (null pokud nelze zjistit) |
error |
string | null | Popis chyby (null při úspěchu) |
Poznámka: Data jsou získávána spuštěním příkazů
points look <jméno>amoney <jméno>a parsováním jejich výstupu. Pokud plugin PlayerPoints nebo Essentials není nainstalován, vrátínull.
HTTP kódy:
200 OK— vždy (i při chybě — chyba je v těle odpovědi)400 Bad Request— pokud chybí parametr{name}v cestě
Interaktivní dokumentace API (OpenAPI 3.0) je dostupná bez autentizace:
http://127.0.0.1:<port>/swagger
OpenAPI specifikace ve formátu YAML se nachází v src/main/resources/openapi/documentation.yaml.
Plugin registruje příkaz /sentrysmp (alias definován v plugin.yml).
sentrysmp.use
Hráči bez tohoto oprávnění obdrží: You do not have permission to use this command.
| Příkaz | Popis |
|---|---|
/sentrysmp holo add all |
Zobrazí celkový store leaderboard (všechny časy) |
/sentrysmp holo add today |
Zobrazí dnešní store leaderboard |
/sentrysmp holo add week |
Zobrazí týdenní store leaderboard |
/sentrysmp holo add month |
Zobrazí měsíční store leaderboard |
/sentrysmp holo remove |
Odstraní váš hologram |
- Hologram se vytvoří na pozici hráče (o 1 blok výše) nebo na spawn lokaci světa (pokud příkaz zadán z konzole).
- Každý hráč může mít aktivní pouze jeden hologram (nový příkaz
addnahradí předchozí). - Hologram se automaticky obnovuje každých
hologram-refresh-secondssekund (výchozí 5 s). - Pokud je
hologram-ttl-seconds > 0, hologram po uplynutí doby zmizí sám. - Po restartu serveru jsou hologramy automaticky obnoveny ze souboru
plugins/SentryAPI/holo-sessions.yml.
/sentrysmp holo add <range>
│
├── HoloCommand.onCommand()
│ ├── Uloží konfiguraci hologramu do holo-sessions.yml
│ └── Volá spawnHologramForKey(key, loc, range)
│
├── [async vlákno] ScoreboardClient.get<Range>()
│ └── HTTP GET na sentrysmp.eu/api/scoreboard/<range>
│
├── [async vlákno] buildLines(entries, player)
│ ├── Sestaví title + subtitle
│ ├── Přidá řádky s rank, prefixem (LuckPerms), jménem, skóre
│ └── Aplikuje PlaceholderAPI (pokud dostupné)
│
└── [hlavní vlákno] HologramRenderer.spawnHologram(loc, lines)
└── Pro každý řádek spawne neviditelný ArmorStand s CustomName
Plugin udržuje dva soubory v plugins/SentryAPI/:
| Soubor | Obsah |
|---|---|
holos.txt |
UUID všech aktivních ArmorStand entit (jeden UUID na řádek) |
holo-sessions.yml |
Konfigurace hologramů (klíč, svět, souřadnice, range) pro obnovu po restartu |
Při startu pluginu (onEnable):
cleanupOrphanedStands()— přečteholos.txt, projde všechny světy a odstraní nalezené entity.restoreHolograms()— přečteholo-sessions.ymla znovu spawne hologramy na původních pozicích.
§c§lSTORE €§r ← červený, tučný titulek
§7ʟᴇᴀᴅᴇʀʙᴏᴀʀᴅ§r ← šedý podtitulek (small caps)
§c1.§r [prefix] Steve §c1234€§r
§c2.§r Alex §c987€§r
... ← až 10 řádků
ScoreboardClient je HTTP klient pro načítání dat scoreboard z https://www.sentrysmp.eu/api.
| Metoda | Endpoint | Popis |
|---|---|---|
getAll() |
/scoreboard/all |
Celkový žebříček |
getToday() |
/scoreboard/today |
Dnešní žebříček |
getWeek() |
/scoreboard/week |
Týdenní žebříček |
getMonth() |
/scoreboard/month |
Měsíční žebříček |
- In-memory cache s konfigurovatelným TTL (
scoreboard-cache-ttl, výchozí 60 s). - Automatický retry — při selhání HTTP požadavku opakuje pokus max. 3×, exponenciální backoff (200 ms → 400 ms → 800 ms).
- Flexibilní parsování — zvládne odpověď jak ve formátu
ScoreboardResponse(objekt s polementries), tak jako holé poleScoreEntry[]. - Při selhání všech pokusů vrací
nulla loguje chybu.
{
"entries": [
{
"rank": 1,
"minecraftUsername": "Steve",
"totalPaid": 1234.5,
"transactionCount": 42,
"lastPayment": "2024-12-01"
}
],
"period": "all"
}Všechny modely jsou v souboru Models.kt a anotovány @Serializable (kotlinx.serialization).
data class CommandRequest(val command: String)data class CommandResponse(val output: List<String>, val success: Boolean)data class PlayerInfo(val name: String, val uuid: String)data class PlayersResponse(val players: List<PlayerInfo>)data class BanEntry(val name: String, val uuid: String, val reason: String?)data class BanlistResponse(val banned: List<BanEntry>)data class PlayerStatsResponse(
val player: String,
val coins: Long? = null,
val money: Double? = null,
val rank: String? = null,
val statistics: PlayerStatistics? = null,
val error: String? = null
)
### PlayerStatistics
```kotlin
data class PlayerStatistics(
val playTimeSeconds: Long? = null,
val playTimeTicks: Long? = null,
val deaths: Long? = null,
val playerKills: Long? = null,
val mobsKilled: Long? = null,
val blocksTravelled: Long? = null
)
### ScoreEntry
```kotlin
data class ScoreEntry(
val rank: Int,
val minecraftUsername: String,
val totalPaid: Double,
val transactionCount: Int,
val lastPayment: String? = null
)
data class ScoreboardResponse(
val entries: List<ScoreEntry> = emptyList(),
val period: String? = null
)Plugin funguje bez těchto závislostí, ale poskytuje rozšířené funkce, pokud jsou přítomny.
- Pokud je LuckPerms aktivní, zobrazí se v hologramovém leaderboardu před jménem hráče jeho prefix (barevně formátovaný).
- Prefix je načten přes
LuckPermsProvider.get()→UserManager→cachedData.getMetaData(). - Pokud hráč není online, UUID je vyhledáno asynchronně.
- Pokud je PlaceholderAPI přítomno, každý řádek hologramu je zpracován přes
PlaceholderAPI.setPlaceholders(player, line). - Integrace je realizována reflexí, takže plugin se zkompiluje i bez PlaceholderAPI na classpath.
Projekt používá Gradle Wrapper — není nutné mít Gradle nainstalovaný.
| Úloha | Příkaz | Popis |
|---|---|---|
| Sestavení | ./gradlew build |
Zkompiluje, sestaví a spustí testy |
| Testy | ./gradlew test |
Spustí pouze unit/integrační testy |
| Kompilace | ./gradlew classes |
Pouze kompilace zdrojových kódů |
| Fat JAR | ./gradlew fatJar |
Vytvoří standalone JAR se všemi závislostmi |
./gradlew fatJarVýstup: build/libs/SentryAPI-1.2-all.jar
JAR obsahuje všechny runtime závislosti (Ktor, Netty, kotlinx.serialization). Paper API a LuckPerms API jsou compileOnly — nesmí být v JAR, protože jsou poskytovány serverem.
| Závislost | Verze | Scope |
|---|---|---|
| Paper API | 1.21.1-R0.1-SNAPSHOT | compileOnly |
| LuckPerms API | 5.4 | compileOnly |
| kotlinx-coroutines-core | 1.9.0 | compileOnly |
| log4j-core | 2.24.1 | compileOnly |
| Ktor server core | 3.4.0 | implementation |
| Ktor server netty | 3.4.0 | implementation |
| Ktor content negotiation | 3.4.0 | implementation |
| Ktor kotlinx-json serialization | 3.4.0 | implementation |
| Ktor swagger | 3.4.0 | implementation |
| kotlinx-serialization-json | 1.5.1 | implementation |
Základní integrační test se nachází v src/test/kotlin/ServerTest.kt.
./gradlew test| Test | Popis |
|---|---|
test root endpoint |
Ověří, že GET / vrátí 200 OK (přes testApplication) |
Test používá AppModule.configure() — odlehčenou konfiguraci Ktor aplikace bez závislosti na Bukkit/Paper.
Server naslouchá pouze na 127.0.0.1. Přístup z internetu není možný přímo. Pokud chcete API zpřístupnit externě, použijte reverse proxy (nginx, Caddy) s HTTPS a případnou IP whitelist.
- Přenášen jako HTTP hlavička
X-API-Key. - Výchozí klíč v
config.ymlje nutné před nasazením změnit. - Klíč je porovnáván prostým porovnáním stringů — pro produkci doporučujeme dlouhý náhodný řetězec (min. 32 znaků).
Endpoint POST /command vykoná jakýkoli příkaz jako konzole (tedy s plnými oprávněními). Přístup k tomuto endpointu musí být přísně omezen. Nikdy nevolávejte tento endpoint s uživatelsky zadaným vstupem bez validace.
saveDefaultConfig()— vytvoříconfig.ymlpokud neexistuje.- Načte
port,api-key,scoreboard-base-url,scoreboard-cache-ttl,hologram-ttl-seconds,hologram-refresh-seconds. - Vytvoří
ScoreboardClient. HoloCommand.cleanupOrphanedStands(plugin)— odstraní přetrvávající ArmorStand entity z předchozí session.- Vytvoří a zaregistruje
HoloCommandjako executor příkazusentrysmp. - Spustí
embeddedServer(Netty, ...)a zavoláserver.start(wait = false). - Naplánuje
holo.restoreHolograms()na příští tick (světy jsou zaručeně načteny).
holoCommand.removeAll()— zruší všechny Bukkit tasky, odstraní ArmorStand entity, smažeholos.txt.httpServer.stop(gracePeriodMillis = 1000, timeoutMillis = 5000)— korektně zastaví Netty server.
- Zkontrolujte, zda port (výchozí 8080) není obsazen jiným procesem:
netstat -tlnp | grep 8080 - Zkontrolujte log serveru na řádky od
SentryAPI.
- Ověřte, že posíláte hlavičku
X-API-Keyse správnou hodnotou zconfig.yml.
- Normální chování — pokud nikdo není online / zabanován.
- Plugin PlayerPoints nebo Essentials není nainstalován nebo hráč neexistuje.
- Zkontrolujte, zda příkazy
points look <jméno>amoney <jméno>fungují v konzoli serveru.
- Ujistěte se, že máte oprávnění
sentrysmp.use. - Zkontrolujte, zda scoreboard API odpovídá (test:
curl https://www.sentrysmp.eu/api/scoreboard/all). - Podívejte se do konzole serveru na chybové výpisy od
ScoreboardClient.
- Soubor
plugins/SentryAPI/holo-sessions.ymlmusí existovat a musí v něm být uložený hologram. - Svět musí existovat (pokud byl svět smazán nebo přejmenován, hologram nelze obnovit).
- Ověřte, že LuckPerms je nainstalován a povolen.
- Prefix musí být nastaven v LuckPerms pomocí
lp user <hráč> meta setprefix <priorita> "<prefix>".