Skript: podstawy skryptowania dla adminów serwerów Minecraft (2026)

Skript: podstawy skryptowania dla adminów serwerów Minecraft (2026)

Skript pozwala dorzucić logikę do serwera bez ani jednej linii Javy. Piszesz prawie po angielsku do pliku .sk, wrzucasz do plugins/Skript/scripts/, robisz /sk reload i działa. Dla admina, który chce dodać powitanie na wejściu, własny /heal, licznik killi albo małą ekonomię bez szukania javowca, to najszybsza droga od pomysłu do działającej mechaniki.

W 2026 aktywna gałąź to Skript 2.9.x i wyżej od ekipy SkriptLang (github.com/SkriptLang/Skript), wspiera Paper 1.21+, Folia tylko w eksperymentalnych branchach. Niżej: instalacja, układ pliku .sk, składnia, dodatki (skBee, skript-yaml, skript-reflect, skquery) i typowe pułapki wydajnościowe.

Czym Skript jest naprawdę i komu się przyda

Skript to plugin-interpreter. Czyta pliki .sk, parsuje je jako DSL wyglądający jak angielski i przekłada na eventy, komendy i efekty Bukkit/Paper. Dla admina to znaczy: mechanikę, na którą inaczej trzeba by szukać programisty, składasz w jeden wieczór.

Komu się to faktycznie opłaca:

  • Admin małego SMP, który potrzebuje 3 do 5 własnych komend i kilku triggerów.
  • Admin publicznego serwera, który chce szybko wystawiać eventy (podwójny XP w weekend, killstreaki, easter eggi).
  • Programista prototypujący pomysł, zanim wejdzie pełen plugin w Javie.

Komu nie: budowniczy systemów walki MMORPG z tysiącami graczy jednocześnie i ciężką logiką per tick. Skript wytrzymuje typowe SMP i minigry, ale gorące ścieżki należy potem przepisać do Javy.

Instalacja i pierwsze /sk reload

Najnowszą wersję bierzesz z GitHub releases na github.com/SkriptLang/Skript/releases albo z Modrintha na modrinth.com/plugin/skript. W 2026 mówimy o Skript 2.9.x na Paper 1.21+.

JAR do plugins/, raz odpalasz serwer, plugin tworzy swój folder. Layout po pierwszym starcie:

plugins/Skript/
├── config.sk              # globalna konfiguracja
├── aliases-english.sk     # nazwy itemów
├── scripts/
│   ├── -disabled-script.sk   # myślnik z przodu = wyłączony
│   └── examples/
└── lang/

Pierwszy plik plugins/Skript/scripts/welcome.sk:

on join:
    send "&aWelcome %player% to the server!" to player
    add 1 to {joins::%player's uuid%}

W konsoli albo w grze z permem skript.admin:

/sk reload welcome

Skript powie ile triggerów wczytał i czy były błędy. Wchodzisz na serwer, widzisz zielone powitanie. To twój pierwszy działający skrypt.

Struktura pliku .sk: events, commands, functions

Plik .sk to stos bloków na top-levelu. Każdy blok zaczyna się w kolumnie 0, wszystko w środku ma wcięcie dokładnie 4 spacje albo 1 tab. Skript jest w tym bezlitosny: mieszanie tabów i spacji w jednym pliku daje inconsistent indentation i plik się nie ładuje.

Trzy typy bloków:

1. Event handler. Reaguje na event serwera.

on death of a player:
    broadcast "&c%victim% died at %location of victim%"

2. Command. Rejestruje własną komendę.

command /fly [<player>]:
    permission: server.fly
    permission message: &cYou cannot fly here.
    trigger:
        if arg-1 is set:
            set {_target} to arg-1
        else:
            set {_target} to player
        if {_target} is flying:
            set flight mode of {_target} to false
            send "&7Flight disabled for &e%{_target}%" to player
        else:
            set flight mode of {_target} to true
            send "&aFlight enabled for &e%{_target}%" to player

3. Function. Logika do reużycia, czyli procedura.

function welcomeMessage(p: player):
    send "&aWelcome back, %{_p}%!" to {_p}
    if difference between {lastSeen::%{_p}'s uuid%} and now is greater than 7 days:
        send "&7You were gone for a while. Server is on Paper 1.21.4 now." to {_p}
    set {lastSeen::%{_p}'s uuid%} to now

on join:
    welcomeMessage(player)

Nazwa pliku nie wpływa na zachowanie, tylko na ergonomię /sk reload <file>. Myślnik z przodu wyłącza skrypt bez kasowania.

Typy danych: player, item, location, block, vector, number, text

Skript jest typowany, ale inferencja robi większość roboty. Podstawy:

TypPrzykładGdzie się pojawia
playerplayer, arg-1, victimevent handlery, cele komend
item1 diamond, player's toolinventory, dropy
locationlocation of player, block's locationteleport, spawn moba
blocktargeted block, event-blockplacement, break
vectorvector(0, 1, 0)velocity, knockback
number42, player's healthliczniki, koordynaty
text"hello", "&a%player%"wiadomości, nazwy
entityattacker, loop-entitymoby, NPC
worldworld "world_nether"sprawdzanie świata
timespan5 seconds, 2 minutesopóźnienia, cooldowny
chatcolorred, &cformatowanie

Konwersje robią wyrażenia typu block at location, location of entity, name of item. Jawne castowanie nie jest potrzebne.

Realny handler on join

Powitanie z wykryciem pierwszego wejścia, wariantem VIP i trackowaniem online:

on first join:
    broadcast "&6%player% &ejoined for the first time! Welcome!"
    give 1 stone pickaxe of efficiency 1 to player
    give 16 cooked beef to player
    teleport player to {spawn}

on join:
    if player has permission "server.vip":
        send "&6&l[VIP] &eWelcome back, %player%" to player
    else:
        send "&aWelcome back, %player%" to player
    add 1 to {stats::joins::%player's uuid%}
    set {stats::lastjoin::%player's uuid%} to now
    wait 2 ticks
    set tab list header "&aServer Online" and footer "&7Players: %size of all players%" for player

on quit:
    set {stats::lastquit::%player's uuid%} to now

first join odpala raz na UUID, join przy każdym wejściu. Nie kolidują, oba lecą dla nowego gracza.

Własne komendy: /heal z permami i argumentami

Skript rejestruje komendy automatycznie przy ładowaniu skryptu, plugin.yml zostawiasz w spokoju.

command /heal [<player>] [<integer>]:
    description: Heals a player to full or to a specific amount
    aliases: /h
    permission: server.heal
    permission message: &cMissing permission &7server.heal
    cooldown: 30 seconds
    cooldown message: &cWait %remaining time% before using /heal again.
    cooldown bypass: server.heal.bypass
    trigger:
        if arg-1 is set:
            if sender does not have permission "server.heal.others":
                send "&cYou cannot heal others." to sender
                stop
            set {_target} to arg-1
        else:
            if sender is not a player:
                send "&cConsole must specify a player." to sender
                stop
            set {_target} to sender
        if arg-2 is set:
            set health of {_target} to arg-2
        else:
            heal {_target}
        feed {_target}
        send "&aHealed %{_target}%" to sender
        if {_target} is not sender:
            send "&aYou were healed by &e%sender%" to {_target}

Co ważne: cooldown jest wbudowany, permission message pokazuje się przy braku perma, aliases daje /h, stop przerywa trigger. Argumenty przez arg-1, arg-2.

Zmienne: lokalne, listy, persystentne

Trzy rodzaje:

Lokalna ({_name}) żyje tylko w bieżącym triggerze albo funkcji:

on damage:
    set {_dmg} to damage
    set {_attacker} to attacker
    if {_dmg} is greater than 10:
        send "Big hit by %{_attacker}%" to victim

Globalna ({name}) jest persystowana do variables.csv i przeżywa restarty:

set {spawn} to location of player
set {server.motd} to "&aPaper 1.21.4"

Listowa/indeksowana ({name::%key%} albo {name::*}) działa jak słownik:

add 1 to {kills::%attacker's uuid%}
loop {kills::*}:
    send "%loop-index%: %loop-value%" to player
clear {kills::%player's uuid%}
delete {kills::%player's uuid%}

Twardy nawyk: zawsze klucz po uuid, nigdy po nicku. Gracz zmieni nick i tracisz dane. Ciężkich obiektów typu pełen inventory nie pakuj do persystentnych zmiennych bez powodu, plik puchnie.

W poważnych projektach przenieś stan persystentny do SQL przez skript-db albo do YAML przez skript-yaml. CSV wytrzyma 50 do 100 tysięcy wpisów, dalej ładowanie boli.

Przydatne dodatki: skBee, skript-yaml, skript-reflect, skquery

Goły Skript pokrywa może 70% potrzeb. Reszta to dodatki.

DodatekDo czegoLink
skBeeNBT, scoreboardy, world border, recipes, fastboards, particlegithub.com/ShaneBeee/skBee
skript-yamlCzytanie i zapis YAMLgithub.com/SkriptLang/skript-yaml
skript-reflectRefleksja Javy (surowe Bukkit API)github.com/TPGamesNL/skript-reflect
skqueryStare rozszerzenia, częściowo pokryte przez skBeegithub.com/Tuke-Nuke/SkQuery
skript-placeholdersMost do PlaceholderAPIgithub.com/APickledWalrus/skript-placeholders
skript-dbMySQL/SQLitegithub.com/btk5h/skript-db

W 2026 skBee 3.x zastępuje większość tego, co kiedyś robił skquery, plus nowoczesne API Papera. Tylko jeden dodatek? Niech to będzie skBee.

Scoreboard ze skBee:

on join:
    create new scoreboard named "stats_%player's uuid%"
    set line 1 of player's scoreboard to "&7&m-----------"
    set line 2 of player's scoreboard to "&aKills: &f%{kills::%player's uuid%} ? 0%"
    set line 3 of player's scoreboard to "&cDeaths: &f%{deaths::%player's uuid%} ? 0%"
    set line 4 of player's scoreboard to "&7&m-----------"
    set title of player's scoreboard to "&6Server Stats"
    set player's displayed scoreboard to player's scoreboard

Typowe wzorce: licznik killi, mała ekonomia, welcome

Licznik killi z topką.

on death of a player:
    if attacker is a player:
        add 1 to {kills::%attacker's uuid%}
        add 1 to {deaths::%victim's uuid%}
        send "&a+1 kill &7(total: %{kills::%attacker's uuid%}%)" to attacker

command /killtop:
    trigger:
        send "&6&l=== Top 10 Killers ===" to player
        set {_sorted::*} to sorted indexes of {kills::*} in descending order
        loop {_sorted::*}:
            if loop-iteration > 10:
                stop loop
            set {_uuid} to loop-value
            set {_name} to name of offline player from uuid {_uuid}
            send "&e%loop-iteration%. &f%{_name}% &7- &c%{kills::%{_uuid}%}% kills" to player

Ekonomia bez Vault.

on join:
    if {money::%player's uuid%} is not set:
        set {money::%player's uuid%} to 100

command /balance [<player>]:
    aliases: /bal, /money
    trigger:
        if arg-1 is set:
            set {_t} to arg-1
        else:
            set {_t} to player
        send "&aBalance of &e%{_t}%&a: &6%{money::%{_t}'s uuid%} ? 0%$" to player

command /pay <player> <integer>:
    trigger:
        if arg-1 is sender:
            send "&cYou cannot pay yourself." to sender
            stop
        if arg-2 is less than 1:
            send "&cAmount must be positive." to sender
            stop
        if {money::%sender's uuid%} is less than arg-2:
            send "&cNot enough money." to sender
            stop
        remove arg-2 from {money::%sender's uuid%}
        add arg-2 to {money::%arg-1's uuid%}
        send "&aPaid &6%arg-2%$ &ato &e%arg-1%" to sender
        send "&aReceived &6%arg-2%$ &afrom &e%sender%" to arg-1

Wydajność i pułapki

Skript jest mocny, ale naiwny kod kładzie TPS. Twarde reguły:

1. Nie loopuj wszystkich graczy co tick.

Źle:

every tick:
    loop all players:
        set action bar of loop-player to "&aServer"

Dobrze:

every 5 seconds:
    loop all players:
        set action bar of loop-player to "&aServer"

Tick to 20 razy na sekundę. Action bar przy 2 do 4 Hz wygląda tak samo i kosztuje rząd wielkości mniej.

2. Async, kiedy się da.

Ciężkie rzeczy (HTTP, duże YAML, SQL) lecą w async:

command /lookup <text>:
    trigger:
        send "&7Looking up..." to player
        set {_p} to player
        execute async:
            set {_data} to text from "https://api.example.com/lookup/%arg-1%"
            execute sync:
                send "&aResult: &f%{_data}%" to {_p}

Bez async serwer zamarza na cały czas requestu.

3. Itemów i inventory nie wciskaj do persystentnych zmiennych bez potrzeby. Serializacja jest droga, variables.csv puchnie. Lootboksy trzymaj jako recepturę (typ plus ilość plus meta), nie żywy ItemStack.

4. wait zamiast zagnieżdżonych every. Źle: every 1 second: w on join:. Dobrze: wait 1 second albo timer na zmiennej.

5. Profilowanie przez spark. /spark profiler --thread server pokazuje, czy Skript zjada tick. Dużo Trigger.execute w stacku oznacza ciężki event handler, prawie zawsze every tick albo gruby on damage.

Debugowanie: /sk reload, /sk debug

Komendy admina, perm skript.admin:

  • /sk reload all przeładowuje wszystkie skrypty.
  • /sk reload <name> ładuje jeden plik (bez .sk).
  • /sk reload config przeczytuje config.sk bez restartu plugina.
  • /sk disable <name> dokleja myślnik i wyładowuje.
  • /sk enable <name> cofa.
  • /sk info pokazuje wersję i listę dodatków.
  • /sk update check sprawdza aktualizacje.

Jeśli skrypt się nie ładuje, błędy lecą do konsoli z numerem linii. Klasyki: zmieszane wcięcie, literówka w nazwie eventu, brak dodatku do składni z forum.

Przy głębszym debugu rzucasz telemetrię:

on damage:
    broadcast "DEBUG: %attacker% hit %victim% for %damage% (final: %final damage%)"
    if attacker is a player:
        broadcast "DEBUG: weapon = %attacker's tool%, projectile = %projectile%"

W produkcji broadcast zamień na send to console albo skasuj. Jest też skUnity Parser do sprawdzenia składni bez ruszania serwera.

FAQ

Czy Skript nadaje się na duży publiczny serwer?

Na typowe PvP/SMP/minigry przy 100 do 300 jednocześnie spokojnie, jeśli trzymasz reguły wydajności. Przy 1000+ jednocześnie z tysiącami eventów na sekundę gorące ścieżki przepisujesz do Javy, a Skript zostaje na rzadkie eventy i własne komendy.

Gdzie szukać gotowych skryptów?

skUnity Forums, SkriptHub, GitHub. Przed deployem czytaj kod. Forum często zawiera ukryty every tick po wszystkich graczach, który zabija TPS.

Czemu Skript krzyczy inconsistent indentation?

Masz mieszane taby i spacje. Otwórz plik w edytorze z włączonym pokazem białych znaków (VS Code: View > Render Whitespace) i wybierz jeden styl. 4 spacje to bezpieczny domyślny.

Co ze zmiennymi po hard crashu?

Skript flushuje variables.csv cyklicznie, domyślnie co 5 minut (save interval w config.sk). 1 minutę da się ustawić, kosztem IO. Naprawdę krytyczny stan przepuść przez skript-db do SQL albo rsynkuj CSV co 10 minut.

Czy Skript działa na Folii?

Stan na 2026: mainline SkriptLang/Skript nie wspiera Folii w pełni, tylko branche eksperymentalne. Serwery region-aware idą z ograniczeniami (brak dostępu cross-region bez właściwego schedulera). Przed migracją sprawdź github.com/SkriptLang/Skript/issues.

Jak chronić serwer ze Skriptem przed DDoS?

Skript pracuje na warstwie eventów gry i z floodami L4 nic nie zrobi. Przed serwer wstaw filtr sieciowy, np. MineGuard. Skript to logika ingame, nie hydraulika pakietowa.

Skript pozostaje najszybszym sposobem zamiany pomysłu w działającą mechanikę bez startu projektu Java. Zainstaluj, napisz pierwszy welcome.sk, potem /heal, potem licznik killi i po tygodniu masz stos własnej logiki dopasowanej do twojego serwera. Tylko trzymaj every tick z dala od ciężkich loopów i nie zapominaj o async, kiedy w grę wchodzi dysk albo sieć.


Chroń swój serwer przed atakami DDoS

Darmowa ochrona z konfiguracją w 5 minut. 1 TB ruchu w zestawie.

Wypróbuj za darmo


Powiązane artykuły