Skript: Scripting-Grundlagen für Minecraft-Server-Admins (2026)

Skript: Scripting-Grundlagen für Minecraft-Server-Admins (2026)

Mit Skript bringst du Serverlogik live, ohne eine Zeile Java zu schreiben. Du tippst nahezu englischen Text in eine .sk-Datei, legst sie nach plugins/Skript/scripts/, machst /sk reload, fertig. Für Admins, die ein Join-Welcome, ein eigenes /heal, einen Killcounter oder eine kleine Wirtschaft brauchen, ohne erst einen Java-Entwickler zu finden, ist das der schnellste Weg von Idee zur funktionierenden Mechanik.

Stand 2026 ist die aktive Linie Skript 2.9.x und höher vom SkriptLang-Team (github.com/SkriptLang/Skript), unterstützt Paper 1.21+, Folia nur in experimentellen Branches. Hier kommen Installation, .sk-Aufbau, Syntax, Addons (skBee, skript-yaml, skript-reflect, skquery) und die typischen Performance-Stolperfallen.

Was Skript wirklich ist und wem es hilft

Skript ist ein Interpreter-Plugin. Es liest .sk-Textdateien, parst sie als DSL, die wie Englisch aussieht, und übersetzt das in Bukkit/Paper-Events, Commands und Effekte. Für dich als Admin heißt das: eine Mechanik, für die du sonst ein Custom-Plugin brauchen würdest, sitzt nach einem Abend.

Wer am meisten profitiert:

  • Kleine SMP-Admins, die 3 bis 5 eigene Commands und ein paar Trigger brauchen.
  • Public-Server-Admins, die Events schnell ausrollen wollen (Doppel-XP-Wochenende, Killstreaks, Easter-Eggs).
  • Entwickler, die eine Idee testen, bevor ein vollwertiges Java-Plugin entsteht.

Wer woanders schauen sollte: Bauer von MMORPG-Kampfsystemen mit Tausenden gleichzeitigen Spielern und dichter Tick-Logik. Skript hält ganz normale SMP- und Minigame-Last problemlos aus, aber heiße Pfade gehören in Java.

Installation und das erste /sk reload

Hol dir die letzte stabile Version von GitHub-Releases auf github.com/SkriptLang/Skript/releases oder Modrinth auf modrinth.com/plugin/skript. 2026 heißt das Skript 2.9.x für Paper 1.21+.

JAR ins plugins/-Verzeichnis legen, Server einmal starten, damit das Plugin seinen Ordner anlegt. Layout nach dem ersten Boot:

plugins/Skript/
├── config.sk              # globale Config
├── aliases-english.sk     # Item-Namen
├── scripts/
│   ├── -disabled-script.sk   # Bindestrich vorne = deaktiviert
│   └── examples/
└── lang/

Erste Datei plugins/Skript/scripts/welcome.sk:

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

In Konsole oder ingame mit Permission skript.admin:

/sk reload welcome

Skript meldet, wie viele Trigger geladen wurden und ob Fehler kamen. Joinst du auf den Server, siehst du die grüne Begrüßung. Das ist dein erstes funktionierendes Skript.

Aufbau einer .sk-Datei: Events, Commands, Functions

Eine .sk-Datei ist ein Stack von Top-Level-Blöcken. Jeder Block beginnt in Spalte 0, alles drinnen ist mit exakt 4 Leerzeichen oder 1 Tab eingerückt. Skript ist da kompromisslos: Tabs und Leerzeichen mischen führt zu inconsistent indentation und die Datei lädt nicht.

Die drei Block-Typen:

1. Event-Handler. Reagiert auf ein Server-Event.

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

2. Command. Registriert einen eigenen Command.

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. Wiederverwendbare Logik wie eine Prozedur.

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)

Der Dateiname ändert nichts am Verhalten, nur wie bequem /sk reload <file> ist. Bindestrich vorn deaktiviert das Skript ohne Löschen.

Datentypen: player, item, location, block, vector, number, text

Skript ist typisiert, aber Inferenz erledigt fast alles. Das Wichtigste:

TypBeispielwertWo es auftaucht
playerplayer, arg-1, victimEvent-Handler, Command-Ziele
item1 diamond, player's toolInventar, Drops
locationlocation of player, block's locationTeleport, Mob-Spawn
blocktargeted block, event-blockPlace, Break
vectorvector(0, 1, 0)Velocity, Knockback
number42, player's healthCounter, Koordinaten
text"hello", "&a%player%"Nachrichten, Namen
entityattacker, loop-entityMobs, NPCs
worldworld "world_nether"Welt-Checks
timespan5 seconds, 2 minutesDelays, Cooldowns
chatcolorred, &cFormatierung

Konvertierung läuft über Ausdrücke wie block at location, location of entity, name of item. Kein explizites Casting nötig.

Realistischer on join Handler

Welcome-Skript mit Erstkontakt-Erkennung, VIP-Variante und Online-Zähler:

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 feuert einmal pro UUID, join bei jedem Login. Kein Konflikt, beide laufen für einen brandneuen Spieler.

Custom Commands: /heal mit Permissions und Argumenten

Skript registriert Commands automatisch beim Laden, du fasst keine plugin.yml an.

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}

Wichtig: cooldown ist eingebaut, permission message zeigt sich bei fehlender Permission, aliases legt /h an, stop bricht den Trigger ab. Argumente kommen über arg-1, arg-2.

Variablen: lokal, Liste, persistent

Drei Sorten:

Lokal ({_name}) lebt nur im aktuellen Trigger oder der Function:

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

Global ({name}) wird in variables.csv persistiert und überlebt Restarts:

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

List/indexed ({name::%key%} oder {name::*}) ist effektiv ein Dict:

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%}

Pflicht-Gewohnheit: immer uuid als Key, niemals den Namen. Spieler tauschen ihren Nick und du verlierst die Daten. Schwere Objekte wie ganze Inventare gehören nicht ohne Grund in persistente Vars, die Datei wird sonst riesig.

Für ernsthafte Projekte: persistenten State über skript-db in SQL oder über skript-yaml in YAML auslagern. Die CSV trägt 50k bis 100k Einträge, danach werden Ladezeiten unangenehm.

Nützliche Addons: skBee, skript-yaml, skript-reflect, skquery

Vanilla-Skript deckt vielleicht 70% ab. Den Rest machen Addons.

AddonZweckLink
skBeeNBT, Scoreboards, Worldborder, Recipes, Fastboards, Particlesgithub.com/ShaneBeee/skBee
skript-yamlYAML lesen und schreibengithub.com/SkriptLang/skript-yaml
skript-reflectDirekte Java-Reflection (Bukkit-API roh)github.com/TPGamesNL/skript-reflect
skqueryÄltere Erweiterungen, überschneidet sich mit skBeegithub.com/Tuke-Nuke/SkQuery
skript-placeholdersBrücke zu PlaceholderAPIgithub.com/APickledWalrus/skript-placeholders
skript-dbMySQL/SQLite-Queriesgithub.com/btk5h/skript-db

2026 ersetzt skBee 3.x das meiste, was früher skquery konnte, plus moderne Paper-APIs. Nur ein Addon? Dann skBee.

skBee-Scoreboard-Beispiel:

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

Typische Patterns: Killcounter, Mini-Wirtschaft, Welcome

Killcounter mit Topliste.

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

Mini-Wirtschaft ohne 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

Performance und Stolperfallen

Skript ist mächtig, naiver Code zerlegt aber TPS. Harte Regeln:

1. Kein Loop über alle Spieler pro Tick.

Schlecht:

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

Gut:

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

Ein Tick sind 20 mal pro Sekunde. Action Bars bei 2 bis 4 Hz sehen identisch aus und kosten eine Größenordnung weniger.

2. Async, wenn möglich.

Schwere Sachen (HTTP-Calls, große YAML-Reads, SQL) gehören in 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}

Ohne async friert der Server für die volle Request-Zeit ein.

3. Pack keine Items oder Inventare in persistente Vars, wenn nicht nötig. Serialisierung ist teuer und bläst variables.csv auf. Lootboxen lieber als Rezept (Type plus Menge plus Meta) speichern, nicht als ItemStack.

4. wait statt geschachtelter every-Blöcke. Schlecht: every 1 second: in on join:. Gut: wait 1 second oder ein Timer per Variable.

5. Profilieren mit spark. /spark profiler --thread server zeigt, ob Skript deinen Tick frisst. Viele Trigger.execute-Frames im Stack heißt schwerer Event-Handler, fast immer ein every tick oder ein fettes on damage.

Debugging: /sk reload, /sk debug

Admin-Commands, Permission skript.admin:

  • /sk reload all lädt alle Skripte neu.
  • /sk reload <name> lädt eine Datei (ohne .sk).
  • /sk reload config zieht config.sk neu, ohne das Plugin zu restarten.
  • /sk disable <name> setzt einen Bindestrich vor und lädt aus.
  • /sk enable <name> macht das rückgängig.
  • /sk info zeigt Version und Addon-Liste.
  • /sk update check prüft auf Updates.

Lädt ein Skript nicht, kommen die Fehler in die Konsole mit genauer Zeile. Klassiker: gemischte Einrückung, Tippfehler im Event, fehlendes Addon für eine Syntax aus dem Forum.

Für tieferes Debug: Telemetrie streuen.

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%"

In Production broadcast durch send to console ersetzen oder rausnehmen. Es gibt auch den skUnity Parser für Syntax-Checks ohne Live-Reload.

FAQ

Eignet sich Skript für einen großen Public-Server?

Für typisches PvP/SMP/Minigame mit 100 bis 300 gleichzeitigen Spielern absolut, solange die Performance-Regeln stehen. Bei 1000+ gleichzeitig mit Tausenden Events pro Sekunde portierst du die heißen Pfade nach Java und behältst Skript für seltene Events und Custom-Commands.

Wo finde ich fertige Skripte?

skUnity Forums, SkriptHub, GitHub. Vor dem Deploy lesen. Forenfunde verstecken oft ein every tick über alle Spieler, das deine TPS halbiert.

Warum schreit Skript inconsistent indentation?

Tabs und Leerzeichen gemischt. Datei in einem Editor mit Whitespace-Anzeige öffnen (VS Code: View > Render Whitespace) und auf einen Stil zwingen. 4 Leerzeichen sind Standard.

Was passiert mit Variablen bei einem Hard-Crash?

Skript flusht variables.csv periodisch, Default 5 Minuten (in config.sk als save interval). 1 Minute geht, kostet aber IO. Wirklich kritischen State über skript-db in SQL pumpen oder die CSV per rsync alle 10 Minuten sichern.

Läuft Skript auf Folia?

Stand 2026 unterstützt der Mainline SkriptLang/Skript Folia nicht voll, nur experimentelle Branches. Region-Aware-Server gehen mit Einschränkungen (kein Cross-Region-Zugriff ohne den richtigen Scheduler). Aktuellen Stand vor dem Umstieg in github.com/SkriptLang/Skript/issues prüfen.

Wie schütze ich einen Skript-lastigen Server vor DDoS?

Skript läuft auf Game-Event-Ebene und macht gegen L4-Floods nichts. Davor gehört ein Netzwerkfilter, zum Beispiel MineGuard. Skript ist Ingame-Logik, nicht Paket-Klempnerei.

Skript bleibt der schnellste Weg, eine Idee in eine echte Mechanik zu verwandeln, ohne ein Java-Projekt aufzusetzen. Installier es, schreib dein erstes welcome.sk, dann /heal, dann den Killcounter, und nach einer Woche hast du einen Stack eigener Logik, exakt zugeschnitten auf deinen Server. Halte nur every tick von schweren Loops fern und vergiss async nicht, sobald Disk oder Netz im Spiel sind.


Schützen Sie Ihren Server vor DDoS-Angriffen

Kostenloser Schutz mit 5-Minuten-Einrichtung. 1 TB Traffic inklusive.

Kostenlos testen


Weitere Artikel