اللوحات والأقراص المخصّصة تحتاج إلى حزمتين، وتثبيت واحدة منهما هو الفشل المعتاد
حزمة البيانات تسجّل المحتوى؛ وحزمة الموارد توفّر الصورة والصوت. حزمة البيانات وحدها تسجّل شيئًا لا شيء له ليراه. إضافةً إلى حدّ 16×16 وما يتحكّم به طول القرص فعليًا.
اللوحات وأقراص الموسيقى كلتاهما سجلات حقيقية في Java الحديثة، ما يعني أنك تستطيع إضافة عناصر جديدة بدل استبدال عناصر الفانيلا. لا شيء تضيفه يزيح لوحة أو قرصًا موجودًا.
العقبة أن المحتوى موزّع على نوعين مختلفين من الحزم، وكلٌّ منهما عديم الفائدة وحده.
ما الذي يذهب أين
حزمة البيانات تسجّل العنصر:
data/<ns>/painting_variant/<id>.json asset_id, width, height, title, author
data/<ns>/jukebox_song/<id>.json sound_event, description, length_in_seconds, comparator_output
حزمة الموارد توفّر ما تراه وتسمعه:
assets/<ns>/textures/painting/<id>.png
assets/<ns>/sounds/<id>.ogg
assets/<ns>/sounds.json
إذا ثبّتّ حزمة البيانات وحدها، فسيُسجَّل المحتوى بنجاح — فهو موجود، ويجده /give، لكن لا توجد صورة ولا صوت. هذه نتيجة أكثر إرباكًا بكثير من فشل صريح، وهي السبب المعتاد في أن لوحة مخصّصة "لم تعمل". الأداة في هذه الصفحة تشحن كليهما في ملف zip واحد تحديدًا حتى لا يمكن فصلهما.
لاحظ ملفَّي pack.mcmeta. إنهما حزمتان منفصلتان بهويتين منفصلتين؛ ولا يوجد صيغة مدمجة تحمل كليهما.
معرّفات السجل أكثر صرامة من أسماء الملفات
يجوز أن يحتوي المعرّف على a-z و0-9 و_ و. و- فقط (إضافةً إلى / للمجلدات الفرعية). أي شيء آخر ويتخطّى اللعبة ذلك الملف بسطر "Invalid path" في السجل — فتُحمَّل الحزمة، ولا يوجد العنصر أبدًا، وهو أمر أصعب في الملاحظة من الفشل. الحروف الكبيرة والمسافات هما ما يوقع الناس عادةً، لأن كليهما عادي تمامًا في اسم الملف الذي سحبته.
اللوحات: حتى 16×16، و17 يكسر الحزمة
لوحات الفانيلا نفسها تتراوح من 1 × 1 إلى 4 × 4 مكعبات، وهذه الأداة تقدّم النطاق نفسه. لكن الصيغة تسمح بأكثر: يقرأ 26.3 قيمة width وheight كمكعبات كاملة من 1 إلى 16، ولوحة 16 × 16 تُحمَّل وتُعلَّق وتبقى على أي جدار يتّسع لـ 16 × 16 مكعبًا — جُرِّب ذلك على خادم 26.3. ما يحدّد بقاء اللوحة هو المساحة لا الحجم: اللوحة التي لا تتّسع حيث عُلِّقت تسقط كعنصر، ولوحة فانيلا 1 × 1 لا شيء خلفها تسقط بالمثل.
وما بعد 16 لا تقيّده اللعبة بل ترفضه. يفشل "width": 17 برسالة "Value must be within range [1;16]"، ويتوقّف تحميل السجل كله معه، ولن يُفتح العالم حتى تُزال الحزمة.
يُعلَن الحجم في JSON عبر width وheight، بالمكعبات. وهو لا يُستنتج من ملف PNG، لذا فلوحة 3 × 1 صورتها مربّعة ملفٌّ صالح يُعرض ممدودًا.
طول القرص ليس مجرّد تسمية
length_in_seconds هو متى تقرّر اللعبة أن المقطع انتهى. بعد ثانية واحدة من الطول المُعلَن يقطع صندوق الموسيقى الصوت، ويوقف نوتات الموسيقى، ويطفئ إشارة الريدستون التي يبعثها أثناء تشغيل الأغنية — بكامل قوّتها، إلى المكعبات حوله، لمدّة ظنّه أن المقطع ما زال يعمل بالضبط.
إذن فطول غير دقيق ليس خطأً شكليًا. أعلِن مقطعًا مدته 200 ثانية على أنه 100 وستُقطع الموسيقى في منتصفها، مع انقطاع الإشارة في اللحظة نفسها؛ وأعلِنه 300 فيُبقي صندوق الموسيقى إشارته مشتعلة خلال 100 ثانية من الصمت. في الحالتين، الريدستون الذي ينتظر انتهاء القرص يعمل في الوقت الخطأ. هذه الأداة تقرأ المدة الحقيقية من الملف بدل أن تطلب منك كتابتها، لهذا السبب تحديدًا.
أما المقارن فيقرأ شيئًا آخر: comparator_output، رقم ثابت واحد من 0 إلى 15 يبقى ما دام القرص في صندوق الموسيقى، سواء كان يعمل أو انتهى. فهو لا يرتفع عبر المقطع، ولا يغيّره الطول — تستخدمه الفانيلا للتمييز بين الأقراص (13 يعطي 1، وقطة 2، وblocks 3).
كما تُكتب المقاطع بـ "stream": true في sounds.json. الموسيقى طويلة، وتحميل مقطع كامل في الذاكرة قبل تشغيله يسبّب تقطيعًا — فالبثّ هو الافتراضي الصحيح لأي شيء بطول قرص، والخيار الخطأ لمؤثر صوتي قصير.