NimBlock लॉग इन करो

प्लगिन का व्याकरण

specVersion 1

NimBlock प्लगिन कोड नहीं है: यह एक JSON फ़ाइल है जो नियमों का वर्णन करती है, जिसे एक बार सबके लिए लिखे गए Paper इंजन द्वारा पढ़ा और चलाया जाता है। यह पेज बिल्कुल यही बताता है कि इसमें क्या लिखने की अनुमति है, और इसके अलावा कुछ भी संभव नहीं है।

एक नियम, बस एक नियम

पूरा व्याकरण एक वाक्य में समा जाता है: जब यह होता है, अगर ये कंडीशन पूरी होती हैं, तो यह करो। एक प्लगिन नियमों की एक सूची है, एक नियम में एक ट्रिगर, शून्य से 20 तक कंडीशन और एक से 50 तक एक्शन होते हैं।

कहीं भी कोई Java जनरेट नहीं होता, न ही कोई कंपाइलेशन होता है: सर्वर एक ऐसा इंजन लोड करता है जो स्पेक को पढ़ता है। यही वह खासियत है जो आगे मायने रखती है, क्योंकि Minecraft के नए वर्शन की कीमत सिर्फ़ एक बार इस इंजन में चुकानी पड़ती है, न कि उससे बने हर प्लगिन में अलग से।

एक स्पेक कैसी दिखती है

{
    "specVersion": 1,
    "name": "स्वागत",
    "rules": [
        {
            "id": "स्वागत",
            "name": "स्वागत संदेश",
            "match": "all",
            "trigger": { "type": "player.join" },
            "conditions": [
                { "type": "player.has_permission", "params": { "permission": "nimblock.vip" } }
            ],
            "actions": [
                { "type": "player.send_message", "params": { "message": "&6स्वागत है, {player}!" } }
            ]
        }
    ]
}

match की वैल्यू all (डिफ़ॉल्ट) या any होती है, और किसी कंडीशन पर "not": true भी लगाया जा सकता है। enabled: false किसी नियम को फ़ाइल में रखता है लेकिन उसे चालू नहीं करता।

व्याकरण, EBNF में

नीचे दी गई टर्मिनल सूचियाँ कैटलॉग से जनरेट की जाती हैं: ये वही आइडेंटिफ़ायर हैं जिन्हें इंजन चला सकता है, कोई हाथ से लिखा गया अनुवाद नहीं।

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

इन प्रोडक्शन नियमों में दो चीज़ें नहीं दिखतीं, क्योंकि उनका संबंध रूप से नहीं बल्कि तालमेल (कोहेरेंस) से है। जिस कंडीशन या एक्शन को किसी प्लेयर की ज़रूरत होती है, वह सिर्फ़ ऐसे ट्रिगर के नीचे लिखी जा सकती है जो कोई प्लेयर देता हो: "खिलाड़ी को ठीक करो" का "हर N सेकंड में" के नीचे कोई मतलब नहीं बनता। और cancel_event सिर्फ़ किसी रद्द किए जा सकने वाले ट्रिगर के नीचे ही लिखा जा सकता है। दोनों को लिखते समय ही अस्वीकार कर दिया जाता है, चलाते समय नहीं।

टेम्पलेट्स

text टाइप के पैरामीटर टेम्पलेट होते हैं: {player} की जगह वह वैल्यू आ जाती है जो ट्रिगर ने दी थी, {{ एक लिटरल ब्रेस देता है, और कलर कोड &a &l ट्रांसलेट हो जाते हैं।

जिस वैरिएबल के बारे में ट्रिगर को कुछ पता नहीं, वह टेक्स्ट नहीं बल्कि एरर है। हर ट्रिगर बताता है कि वह क्या देता है (नीचे दी गई सूची देखें): इस सूची से बाहर पढ़ने के लिए कुछ नहीं है, और टाइपिंग की गलती को लिखते समय ही अस्वीकार कर दिया जाता है, ताकि वह खिलाड़ियों के चैट में न पहुँच जाए। किसी ट्रिगर के अपने पैरामीटर टेम्पलेट नहीं होते: वे सर्वर के शुरू होते समय पढ़े जाते हैं, उससे पहले कि कुछ भी बदलने के लिए मौजूद हो।

Minecraft के नाम दो तरीकों से लिखे जाते हैं, यह इस पर निर्भर करता है कि वे किसे दर्शाते हैं। किसी आइटम को दोनों वर्तनी में लिखा जा सकता है (DIAMOND_SWORD या diamond_sword)। किसी साउंड या इफ़ेक्ट को उसकी Minecraft की-की (entity.player.levelup, speed) से लिखा जाता है, Bukkit के कॉन्स्टेंट से नहीं: यह की क्लाइंट तक ज्यों की त्यों पहुँचती है, और वर्शन बदलने पर भी बनी रहती है।

व्याकरण जो अनुमति नहीं देता

यह बंद (closed) है, और यह बाकी सब से पहले कह देना ज़रूरी है। कैटलॉग में जो है वह किया जा सकता है, बाकी सब नामुमकिन है और नामुमकिन ही रहेगा: मनमाना Java चलाने का कोई तरीका नहीं है। यही वजह है कि स्टूडियो तुरंत काम करता है (कुछ भी कंपाइल नहीं करना पड़ता) और कोई भी स्पेक, चाहे वह कहीं से भी आई हो, इंस्टॉल करने में हानिरहित है।

कंडीशन नेस्ट नहीं होतीं: यह वर्शन 1 की जान-बूझकर रखी गई सीमा है, कोई बूलियन ट्री ब्लॉक्स में ठीक से नहीं बनता, और all / any / not लगभग हमेशा काफ़ी होते हैं। इससे बाहर निकलने का एक ही रास्ता है: "कंसोल के तौर पर एक कमांड चलाओ" एक्शन, जिसके पास उस सर्वर पर ठीक उतनी ही ताक़त होती है जितनी कंसोल के पास होती है, न कम न ज़्यादा।

ट्रिगर

जो किसी नियम को शुरू करता है, और हर ट्रिगर टेम्पलेट के लिए जो वैरिएबल देता है।

player.join एक खिलाड़ी जुड़ता है

जिस पल खिलाड़ी सर्वर पर आता है, उसकी वर्ल्ड लोड होने के बाद।

देता है: {player} जुड़ने वाला खिलाड़ी, {world} जिस वर्ल्ड में वह आता है

player.quit एक खिलाड़ी छोड़ता है

जिस पल खिलाड़ी सर्वर छोड़ता है। वह अब भी पहुँच में है, लेकिन भेजा गया कोई भी मैसेज खो जाता है।

देता है: {player} जाने वाला खिलाड़ी, {world} जो वर्ल्ड वह छोड़ता है

player.chat एक खिलाड़ी चैट में लिखता है रद्द करने योग्य

मैसेज बाकी खिलाड़ियों तक पहुँचने से पहले। रद्द किया जा सकता है: ऐसे में मैसेज किसी को नहीं दिखता।

देता है: {player} मैसेज लिखने वाला, {world} उसकी वर्ल्ड, {message} लिखा गया मैसेज

player.death एक खिलाड़ी मरता है

खिलाड़ी की मौत पर, रीस्पॉन स्क्रीन आने से पहले।

देता है: {player} मरने वाला खिलाड़ी, {world} उसकी वर्ल्ड, {killer} जिम्मेदार खिलाड़ी, अगर कोई नहीं है तो खाली

player.respawn एक खिलाड़ी रीस्पॉन होता है

जब खिलाड़ी मरने के बाद फिर से गेम में लौटता है।

देता है: {player} रीस्पॉन होने वाला खिलाड़ी, {world} रीस्पॉन वाली वर्ल्ड

block.break एक खिलाड़ी ब्लॉक तोड़ता है रद्द करने योग्य

ब्लॉक गायब होने से पहले। रद्द किया जा सकता है: ब्लॉक अपनी जगह बना रहता है।

देता है: {player} तोड़ने वाला खिलाड़ी, {world} उसकी वर्ल्ड, {block} ब्लॉक का प्रकार (DIAMOND_ORE), {x} ब्लॉक का X निर्देशांक, {y} ब्लॉक की ऊँचाई, {z} ब्लॉक का Z निर्देशांक

block.place एक खिलाड़ी ब्लॉक रखता है रद्द करने योग्य

ब्लॉक रखे जाने से पहले। रद्द किया जा सकता है: ब्लॉक नहीं रखा जाता।

देता है: {player} रखने वाला खिलाड़ी, {world} उसकी वर्ल्ड, {block} रखे गए ब्लॉक का प्रकार, {x} ब्लॉक का X निर्देशांक, {y} ब्लॉक की ऊँचाई, {z} ब्लॉक का Z निर्देशांक

command एक खिलाड़ी कमांड टाइप करता है

सर्वर पर एक नई कमांड बनाता है। ⚠️ जिस कमांड का नाम पहले मौजूद नहीं था, वह सर्वर के दोबारा शुरू होने पर ही दिखती है: Paper नए कमांड नाम केवल स्टार्टअप पर स्वीकार करता है। रूल का कंटेंट, इसके उलट, बिना रीस्टार्ट के रीलोड हो जाता है।

  • name text कमांड का नाम, स्लैश के बिना
  • description text वैकल्पिक हेल्प में दिखने वाला विवरण
  • permission text वैकल्पिक जरूरी परमिशन, सबके लिए खाली

देता है: {player} कमांड टाइप करने वाला खिलाड़ी, {world} उसकी वर्ल्ड, {args} कमांड के बाद जो लिखा गया, ज्यों का त्यों

schedule.repeat हर N सेकंड में

जब तक सर्वर चलता है, रूल को दोहराता है। कोई खिलाड़ी शामिल नहीं होता: सिर्फ वे ऐक्शन इस्तेमाल हो सकते हैं जिन्हें खिलाड़ी की जरूरत नहीं।

  • seconds integer [1..86400] अंतराल, सेकंड में

कंडीशन

जो फ़िल्टर करता है। हर नियम में शून्य से 20 तक, जिन्हें match से जोड़ा जाता है।

player.has_permission खिलाड़ी के पास परमिशन है खिलाड़ी चाहिए
  • permission text परमिशन
player.is_op खिलाड़ी ऑपरेटर है खिलाड़ी चाहिए
player.in_world खिलाड़ी इस वर्ल्ड में है खिलाड़ी चाहिए
  • world text वर्ल्ड का नाम
player.health_below खिलाड़ी के पास X दिलों से कम हैं खिलाड़ी चाहिए

हेल्थ पॉइंट में: 20 पॉइंट 10 दिलों के बराबर होते हैं।

  • value number [0..1024] हेल्थ पॉइंट
text.contains एक टेक्स्ट में शामिल है
  • text text जाँचा गया टेक्स्ट
  • search text जो उसमें खोजा जा रहा है
  • ignoreCase boolean वैकल्पिक, डिफ़ॉल्ट: true बड़े-छोटे अक्षरों को अनदेखा करें
text.equals एक टेक्स्ट बराबर है
  • text text जाँचा गया टेक्स्ट
  • value text अपेक्षित वैल्यू
  • ignoreCase boolean वैकल्पिक, डिफ़ॉल्ट: true बड़े-छोटे अक्षरों को अनदेखा करें
number.compare दो नंबरों की तुलना करें

दोनों पक्ष टेम्पलेट होते हैं: {y} की तुलना 62 से बिना कोई कोड लिखे की जा सकती है।

  • left text बायाँ पक्ष
  • operator < | <= | == | != | >= | > तुलना
  • right text दायाँ पक्ष
chance रैंडम रूप से, X% समय
  • percent number [0..100] प्रतिशत

एक्शन

जो होता है। हर नियम में एक से 50 तक, जो क्रम में चलाए जाते हैं।

player.send_message खिलाड़ी को मैसेज भेजें खिलाड़ी चाहिए
  • message text मैसेज
player.send_actionbar ऐक्शन बार के ऊपर मैसेज दिखाएँ खिलाड़ी चाहिए
  • message text मैसेज
player.send_title बड़ा टाइटल दिखाएँ खिलाड़ी चाहिए
  • title text टाइटल
  • subtitle text वैकल्पिक सबटाइटल
  • fadeIn number [0..60] वैकल्पिक, डिफ़ॉल्ट: 0.5 दिखने में लगने वाला समय, सेकंड में
  • stay number [0..600] वैकल्पिक, डिफ़ॉल्ट: 3 समय, सेकंड में
  • fadeOut number [0..60] वैकल्पिक, डिफ़ॉल्ट: 0.5 गायब होने में लगने वाला समय, सेकंड में
player.play_sound खिलाड़ी के लिए साउंड बजाएँ खिलाड़ी चाहिए
  • sound identifier साउंड, Minecraft की-नेम में (entity.player.levelup)
  • volume number [0..10] वैकल्पिक, डिफ़ॉल्ट: 1 वॉल्यूम
  • pitch number [0.5..2] वैकल्पिक, डिफ़ॉल्ट: 1 पिच
player.give_item खिलाड़ी को आइटम दें खिलाड़ी चाहिए

जो इन्वेंट्री में नहीं समाता, वह उसके पैरों के पास ज़मीन पर गिर जाता है।

  • material identifier आइटम (DIAMOND_SWORD)
  • amount integer [1..2304] वैकल्पिक, डिफ़ॉल्ट: 1 मात्रा
player.give_effect खिलाड़ी पर इफ़ेक्ट लगाएँ खिलाड़ी चाहिए
  • effect identifier इफ़ेक्ट, Minecraft की-नेम में (night_vision)
  • seconds integer [1..86400] वैकल्पिक, डिफ़ॉल्ट: 10 समय, सेकंड में
  • amplifier integer [0..255] वैकल्पिक, डिफ़ॉल्ट: 0 लेवल, 0 से शुरू
player.heal खिलाड़ी को ठीक करें खिलाड़ी चाहिए

हेल्थ पूरी, भूख शांत।

player.teleport खिलाड़ी को टेलीपोर्ट करें खिलाड़ी चाहिए
  • x number [-30000000..30000000] X निर्देशांक
  • y number [-512..1024] ऊँचाई
  • z number [-30000000..30000000] Z निर्देशांक
  • world text वैकल्पिक वर्ल्ड, खिलाड़ी की अपनी वर्ल्ड के लिए खाली
player.kick खिलाड़ी को किक करें खिलाड़ी चाहिए
  • reason text दिखाई जाने वाली वजह
broadcast पूरे सर्वर पर घोषणा करें
  • message text मैसेज
server.run_command कंसोल की तरह कमांड चलाएँ

व्याकरण का आख़िरी रास्ता: जो कुछ कंसोल कर सकता है। इस सर्वर पर कंसोल की पूरी ताकत, इसलिए सोच-समझकर ही लिखें।

  • command text कमांड, स्लैश के बिना
cancel_event जो अभी हुआ उसे रद्द करें रद्द करने योग्य ट्रिगर चाहिए

यह सिर्फ उन ट्रिगर्स पर मौजूद होता है जिन्हें रद्द किया जा सकता है: मैसेज नहीं भेजा जाता, ब्लॉक नहीं टूटता।

log सर्वर के कंसोल में लिखें
  • message text मैसेज
  • level info | warn वैकल्पिक, डिफ़ॉल्ट: info लेवल
delay इंतज़ार करें

रूल के बाकी ऐक्शन को रोक देता है। जो रूल इंतज़ार करता है वह अब कुछ भी रद्द नहीं कर सकता: "रद्द करें" इससे पहले आना चाहिए।

  • seconds number [0.05..3600] सेकंड

प्रकाशित फ़ाइलें

JSON Schema हर डिप्लॉय पर कैटलॉग से जनरेट होता है, और यह मशीन द्वारा पढ़ा जा सकने वाला संदर्भ है: जो एडिटर इसका पालन करता है, वह आइडेंटिफ़ायर ऑटो-कम्प्लीट करता है और अनजान पैरामीटर को अस्वीकार कर देता है।

  • plugin-1.schema.json : स्कीमा, JSON Schema draft 2020-12।
  • catalogue-1.json : ख़ुद कैटलॉग, वह सोर्स जिससे बाक़ी सब कुछ बनता है (वैलिडेटर, स्कीमा, एडिटर के ब्लॉक्स और Java इंजन)।

कैटलॉग में लेबल फ़्रेंच में हैं, क्योंकि फ़्रेंच सोर्स भाषा है। आइडेंटिफ़ायर का अनुवाद नहीं किया जाता: इंजन इन्हीं को चलाता है।

जब व्याकरण बदलता है तो क्या होता है

कोई नया ट्रिगर, कंडीशन या एक्शन जोड़ने से कुछ नहीं टूटता: पहले से लिखी गई कोई स्पेक चलती रहती है। लेकिन कोई ब्रेकिंग चेंज specVersion को बढ़ा देता है, और उसके बाद इंजन जो नहीं समझता उसे ग़लत तरीके से चलाने के बजाय अस्वीकार कर देता है, और इसे सर्वर के कंसोल में बता देता है।

ऊपर दिए गए URL इसी नंबर को साथ लेकर चलते हैं: plugin-1.schema.json हमेशा इसी व्याकरण को दर्शाएगा, भले ही किसी दिन कोई और वर्शन मौजूद हो जाए।