NimBlock Logga in

Plugin-grammatiken

specVersion 1

Ett NimBlock-plugin är inte kod: det är en JSON-fil som beskriver regler, läst och körd av en Paper-motor skriven en gång för alla. Den här sidan säger exakt vad man får skriva i den, och inget annat är möjligt.

En regel, och bara en regel

Hela grammatiken ryms i en enda mening: när detta händer, om dessa villkor gäller, gör då detta. Ett plugin är en lista med regler, en regel är en utlösare, noll till 20 villkor och en till 50 åtgärder.

Ingen Java genereras någonstans, och inget kompileras: servern laddar en motor som läser specen. Det är den egenskap som spelar roll längre fram, för en ny Minecraft-version betalas bara en gång, i den motorn, och inte i varje plugin som skrivits med den.

Hur en spec ser ut

{
    "specVersion": 1,
    "name": "Välkommen",
    "rules": [
        {
            "id": "valkommen",
            "name": "Välkomstmeddelande",
            "match": "all",
            "trigger": { "type": "player.join" },
            "conditions": [
                { "type": "player.has_permission", "params": { "permission": "nimblock.vip" } }
            ],
            "actions": [
                { "type": "player.send_message", "params": { "message": "&6Välkommen {player}!" } }
            ]
        }
    ]
}

match är antingen all (standard) eller any, och ett villkor kan ha "not": true. enabled: false behåller en regel i filen utan att aktivera den.

Grammatiken, i EBNF

Terminallistorna nedan genereras från katalogen: det är bokstavligen de identifierare som motorn kan köra, inte en handskriven avskrift.

<plugin>       ::= "{" "specVersion" ":" 1 ","
                       [ "id" ":" <slug64> "," ]
                       "name" ":" <label> ","
                       [ "description" ":" <text500> "," ]
                       "rules" ":" "[" <rule> { "," <rule> } "]" "}"      (* 1..200 *)

<rule>         ::= "{" [ "id" ":" <slug32> "," ]
                       "name" ":" <label> ","
                       [ "enabled" ":" <boolean> "," ]                   (* = true *)
                       [ "match" ":" ( "all" | "any" ) "," ]              (* = "all" *)
                       "trigger" ":" <trigger> ","
                       [ "conditions" ":" "[" [ <condition>
                             { "," <condition> } ] "]" "," ]              (* 0..20 *)
                       "actions" ":" "[" <action>
                             { "," <action> } "]" "}"                     (* 1..50 *)

<trigger>      ::= "{" "type" ":" <trigger-id>   [ "," "params" ":" <params> ] "}"
<condition>    ::= "{" "type" ":" <condition-id> [ "," "not" ":" <boolean> ]
                                                 [ "," "params" ":" <params> ] "}"
<action>       ::= "{" "type" ":" <action-id>    [ "," "params" ":" <params> ] "}"

<params>       ::= "{" [ <param-name> ":" <param-value>
                       { "," <param-name> ":" <param-value> } ] "}"
<param-value>  ::= <template> | <identifier> | <integer> | <number>
                 | <boolean> | <choice>

<template>     ::= { <literal> | <variable> | <colour> }                (* 0..2000 *)
<literal>      ::= /[^{}]/ | "{{" | "}}"
<variable>     ::= "{" /[a-zA-Z][a-zA-Z0-9_]*/ "}"
<colour>       ::= "&" ( "0".."9" | "a".."f" | "k".."o" | "r" )

<identifier>   ::= /[A-Za-z][A-Za-z0-9_:.\/-]{0,63}/
<slug32>       ::= /[A-Za-z0-9_-]{1,32}/
<slug64>       ::= /.{0,64}/
<label>        ::= /.{1,64}/
<text500>      ::= /.{0,500}/

<trigger-id>   ::= "player.join"
                 | "player.quit"
                 | "player.chat"
                 | "player.death"
                 | "player.respawn"
                 | "block.break"
                 | "block.place"
                 | "command"
                 | "schedule.repeat"
<condition-id> ::= "player.has_permission"
                 | "player.is_op"
                 | "player.in_world"
                 | "player.health_below"
                 | "text.contains"
                 | "text.equals"
                 | "number.compare"
                 | "chance"
<action-id>    ::= "player.send_message"
                 | "player.send_actionbar"
                 | "player.send_title"
                 | "player.play_sound"
                 | "player.give_item"
                 | "player.give_effect"
                 | "player.heal"
                 | "player.teleport"
                 | "player.kick"
                 | "broadcast"
                 | "server.run_command"
                 | "cancel_event"
                 | "log"
                 | "delay"

Två saker syns inte i dessa produktionsregler, eftersom de handlar om samstämmighet och inte om form. Ett villkor eller en åtgärd som kräver en spelare kan bara skrivas under en utlösare som tillhandahåller en: ”läka spelaren” är meningslöst under ”var N:e sekund”. Och cancel_event kan bara skrivas under en avbrytbar utlösare. Båda avvisas vid skrivandet, inte vid körning.

Mallar

Parametrar av typen text är mallar: {player} ersätts där med det som utlösaren tillhandahöll, {{ ger en bokstavlig klammerparentes, och färgkoderna &a &l översätts.

En variabel som utlösaren inte känner till är ett fel, inte text. Varje utlösare deklarerar vad den tillhandahåller (se listan nedan): utanför den listan finns inget att läsa, och ett skrivfel avvisas när man skriver istället för att hamna i spelarnas chatt. En utlösares egna parametrar är däremot inte mallar: de läses när servern startar, innan det finns något alls att ersätta.

Minecraft-namn skrivs på två sätt beroende på vad de anger. Ett föremål namnges i båda stavningarna (DIAMOND_SWORD eller diamond_sword). Ett ljud eller en effekt namnges med sin Minecraft-nyckel (entity.player.levelup, speed) och inte med Bukkit-konstanten: nyckeln skickas oförändrad till klienten och den överlever versionsbyten.

Vad grammatiken inte tillåter

Den är stängd, och det ska sägas först. Det som finns i katalogen går att göra, resten är omöjligt och kommer att förbli det: det finns inget sätt att köra godtycklig Java. Det är det som gör studion omedelbar (inget att kompilera) och en spec ofarlig att installera, oavsett varifrån den kommer.

Villkor kan inte nästlas: det är en medveten begränsning i version 1, ett booleskt träd låter sig inte rita fint i block, och all / any / not räcker nästan alltid. Den enda utvägen är åtgärden ”kör ett kommando som konsolen”, som på just den servern har exakt konsolens makt, varken mer eller mindre.

Utlösare

Det som utlöser en regel, och de variabler som var och en tillhandahåller till mallarna.

player.join En spelare går med

I samma stund som spelaren kommer in på servern, efter att deras värld har laddats.

ger: {player} Spelaren som går med, {world} Världen spelaren kommer till

player.quit En spelare lämnar

I samma stund som spelaren lämnar servern. Spelaren går fortfarande att nå, men alla meddelanden som skickas går förlorade.

ger: {player} Spelaren som lämnar, {world} Världen spelaren lämnar

player.chat En spelare skriver i chatten avbrytbar

Innan meddelandet skickas till de andra spelarna. Kan avbrytas: ingen ser då meddelandet.

ger: {player} Den som skrev meddelandet, {world} Spelarens värld, {message} Meddelandet som skrevs

player.death En spelare dör

Vid spelarens död, innan återuppståndelseskärmen.

ger: {player} Spelaren som dog, {world} Spelarens värld, {killer} Spelaren som var ansvarig, tom om det inte finns någon

player.respawn En spelare återuppstår

När spelaren kommer tillbaka in i spelet efter döden.

ger: {player} Spelaren som återuppstår, {world} Världen spelaren återuppstår i

block.break En spelare bryter ett block avbrytbar

Innan blocket försvinner. Kan avbrytas: blocket blir kvar.

ger: {player} Spelaren som bryter, {world} Spelarens värld, {block} Blocktypen (DIAMOND_ORE), {x} Blockets X-koordinat, {y} Blockets höjd, {z} Blockets Z-koordinat

block.place En spelare placerar ett block avbrytbar

Innan blocket placeras. Kan avbrytas: blocket placeras inte.

ger: {player} Spelaren som placerar, {world} Spelarens värld, {block} Blocktypen som placeras, {x} Blockets X-koordinat, {y} Blockets höjd, {z} Blockets Z-koordinat

command En spelare skriver ett kommando

Skapar ett nytt kommando på servern. ⚠️ Ett kommando vars namn inte fanns sedan tidigare visas först efter en omstart av servern: Paper accepterar bara nya kommandonamn vid uppstart. Regelns innehåll däremot laddas om utan omstart.

  • name text Kommandots namn, utan snedstrecket
  • description text valfritt Beskrivning som visas i hjälpen
  • permission text valfritt Behörighet som krävs, tom för alla

ger: {player} Spelaren som skrev kommandot, {world} Spelarens värld, {args} Det som följer efter kommandot, oförändrat

schedule.repeat Var N:e sekund

Upprepar regeln så länge servern körs. Ingen spelare är inblandad: bara åtgärder som inte behöver någon kan användas.

  • seconds integer [1..86400] Intervall i sekunder

Villkor

Det som filtrerar. Noll till 20 per regel, kombinerade med match.

player.has_permission Spelaren har behörigheten kräver en spelare
  • permission text Behörighet
player.is_op Spelaren är operatör kräver en spelare
player.in_world Spelaren är i världen kräver en spelare
  • world text Världens namn
player.health_below Spelaren har färre än X hjärtan kräver en spelare

I hälsopoäng: 20 poäng motsvarar 10 hjärtan.

  • value number [0..1024] Hälsopoäng
text.contains En text innehåller
  • text text Texten som undersöks
  • search text Det som söks efter
  • ignoreCase boolean valfritt, standard: true Ignorera skiftläge
text.equals En text är lika med
  • text text Texten som undersöks
  • value text Förväntat värde
  • ignoreCase boolean valfritt, standard: true Ignorera skiftläge
number.compare Jämför två tal

Båda sidorna är mallar: {y} jämförs med 62 utan att skriva någon kod.

  • left text Vänster sida
  • operator < | <= | == | != | >= | > Jämförelse
  • right text Höger sida
chance Slumpmässigt, X % av tiden
  • percent number [0..100] Procent

Åtgärder

Det som händer. En till 50 per regel, körda i ordning.

player.send_message Skicka ett meddelande till spelaren kräver en spelare
  • message text Meddelande
player.send_actionbar Visa ett meddelande ovanför åtgärdsfältet kräver en spelare
  • message text Meddelande
player.send_title Visa en titel i stor text kräver en spelare
  • title text Titel
  • subtitle text valfritt Undertitel
  • fadeIn number [0..60] valfritt, standard: 0.5 Intoning i sekunder
  • stay number [0..600] valfritt, standard: 3 Varaktighet i sekunder
  • fadeOut number [0..60] valfritt, standard: 0.5 Uttoning i sekunder
player.play_sound Spela ett ljud för spelaren kräver en spelare
  • sound identifier Ljud, som en Minecraft-nyckel (entity.player.levelup)
  • volume number [0..10] valfritt, standard: 1 Volym
  • pitch number [0.5..2] valfritt, standard: 1 Tonhöjd
player.give_item Ge spelaren ett föremål kräver en spelare

Det som inte får plats i inventariet hamnar på marken vid spelarens fötter.

  • material identifier Föremål (DIAMOND_SWORD)
  • amount integer [1..2304] valfritt, standard: 1 Antal
player.give_effect Ge spelaren en effekt kräver en spelare
  • effect identifier Effekt, som en Minecraft-nyckel (night_vision)
  • seconds integer [1..86400] valfritt, standard: 10 Varaktighet i sekunder
  • amplifier integer [0..255] valfritt, standard: 0 Nivå, från 0
player.heal Hela spelaren kräver en spelare

Full hälsa, mätt hunger.

player.teleport Teleportera spelaren kräver en spelare
  • x number [-30000000..30000000] X-koordinat
  • y number [-512..1024] Höjd
  • z number [-30000000..30000000] Z-koordinat
  • world text valfritt Värld, tom för spelarens egen
player.kick Sparka ut spelaren kräver en spelare
  • reason text Anledning som visas
broadcast Meddela hela servern
  • message text Meddelande
server.run_command Kör ett kommando som konsolen

Grammatikens nödutgång: allt som konsolen kan göra. Det är konsolens fulla makt över den här servern, så skriv det med vetskap om vad du gör.

  • command text Kommando, utan snedstrecket
cancel_event Avbryt det som just hände kräver en avbrytbar utlösare

Finns bara på avbrytbara utlösare: meddelandet skickas inte, blocket bryts inte.

log Skriv till serverns konsol
  • message text Meddelande
  • level info | warn valfritt, standard: info Nivå
delay Vänta

Pausar resten av regelns åtgärder. En regel som väntar kan inte längre avbryta något: "Avbryt" måste komma före.

  • seconds number [0.05..3600] Sekunder

De publicerade filerna

JSON Schema genereras från katalogen vid varje driftsättning, och det är den maskinläsbara referensen: en textredigerare som följer det kompletterar identifierare och avvisar okända parametrar.

Katalogen har etiketterna på franska, som är källspråket. Identifierarna däremot översätts inte: det är de som motorn kör.

Vad som händer när grammatiken ändras

Att lägga till en utlösare, ett villkor eller en åtgärd förstör inget: en spec skriven innan fortsätter att fungera. En brytande ändring ökar däremot specVersion, och motorn vägrar då det den inte förstår istället för att köra det fel, och säger det i serverns konsol.

Webbadresserna ovan bär det här numret: plugin-1.schema.json kommer alltid att peka på just den här grammatiken, även den dag det finns en annan.