Skip to content

Як написати плагін ​

Плагін малий. Він має ім'я і одну функцію, build, яка повертає частку плагіна в маніфесті. Якщо ви можете описати бажане як «ці файли, ці змінні, ці аргументи», ви можете написати це як плагін просто у вашій конфігурації.

Форма ​

js
import { definePlugin } from '@opys/dev';

const myPlugin = (options) =>
  definePlugin({
    name: 'myPlugin',
    async build(ctx) {
      return {
        artifacts: [], // файли для встановлення
        vars: {}, // змінні
        envs: {}, // змінні середовища для гри
        launch: {}, // іменовані фрагменти командного рядка
      };
    },
  });

Кожне поле необов'язкове. Повертайте лише те, що маєте.

build отримує малий контекст:

ПолеЩо це
ctx.log(scope, message)Друкує рядок [scope] message під час збирання.
ctx.configDirТека файла конфігурації. Зіставляйте відносні шляхи з нею.
ctx.modeЗначення --mode.

Одне правило про структуру: виклик плагіна нічого не робить.myPlugin({ … }) лише повертає { name, build }. Уся справжня робота, включаючи мережеві запити і читання файлів, відбувається всередині build. Це тримає конфігурацію дешевою для завантаження і дозволяє opys запускати всі плагіни разом.

Розібраний приклад ​

Цей плагін робить усього по одному: задає змінну, додає файл за URL, додає згенерований файл і пропонує аргумент JVM.

mjs
import { defineConfig, definePlugin, userDataDir } from '@opys/dev';
import { java, minecraft } from '@opys/minecraft';

// A plugin is { name, build(ctx) }. Calling welcome() does no I/O; the work
// happens in build(), which the engine runs once per `opys build`.
const welcome = (motd) =>
  definePlugin({
    name: 'welcome',
    build(ctx) {
      ctx.log('welcome', `motd is "${motd}"`);

      // A generated file. It is carried in the bundle: the build names it by
      // its content, so there is nothing to hash or keep track of here.
      const config = new TextEncoder().encode(`motd = "${motd}"\n`);

      return {
        vars: { motd },
        artifacts: [
          {
            path: '${root}/downloads/brigadier-1.3.10.jar',
            source: {
              url: 'https://libraries.minecraft.net/com/mojang/brigadier/1.3.10/brigadier-1.3.10.jar',
            },
            size: 80082,
            integrity: { sha1: 'd15b53a14cf20fdcaa98f731af5dda654452c010' },
          },
          { path: '${root}/config/welcome.toml', source: { bytes: config } },
        ],
        launch: { jvmArg: '-Dwelcome.motd=${motd}' },
      };
    },
  });

export default defineConfig({
  output: 'game.opys',
  plugins: [
    minecraft({ version: '1.21.1' }),
    java({ version: '21' }),
    welcome('Hello from opys'),
  ],
  manifest: {
    command: '@minecraft.command',
    args: [
      '@welcome.jvmArg',
      '@minecraft.jvmArgs',
      '@minecraft.mainClass',
      '@minecraft.gameArgs',
    ],
    workdir: '${game_directory}',
  },
  run: (manifest) => ({
    manifest: {
      vars: {
        ...manifest.vars,
        root: userDataDir('my-pack'),
        username: 'Player',
        uuid: '00000000-0000-0000-0000-000000000001',
        token: '0',
      },
    },
  }),
});

Розбираємо те, що повертає build:

vars стають змінними маніфесту. Тут motd потім можна використовувати як ${motd} будь-де.

artifacts це файли. Перший це завантаження: шлях, URL і хеш, який він мусить мати. Завжди давайте хеш. Файл без нього не можна перевірити, і він ніколи не оновлюється, коли вже існує.

Другий артефакт привезений: файл, що подорожує всередині бандла. Його джерело каже, де байти просто зараз, у пам'яті ({ bytes }) або у файлі ({ file: path }). Збирання читає їх, називає за їхнім sha256 і зберігає в бандлі. Нічого хешувати самостійно.

launch пропонує іменовані фрагменти командного рядка. Оскільки плагін зветься welcome і пропонує jvmArg, конфігурація може писати '@welcome.jvmArg'. З definePlugin TypeScript теж знає це ім'я, і одрук у конфігурації підсвічується, коли ви друкуєте.

Фрагмент запуску може бути рядком, списком або обмеженим платформою:

js
launch: {
  jvmArgs: [
    '-Dfoo=bar',
    { rules: 'allow.os.osx', value: ['-XstartOnFirstThread'] },
  ],
},

Яким має бути добрий плагін ​

  • Вирішуйте все у build. Маніфест ніколи не каже «найновіша версія». Дізнайтеся версію, URL і хеш під час збирання і запишіть точні відповіді.
  • Фіксуйте кожен файл. Якщо ніхто не публікує хеш для нього, завантажте його у build і хешуйте самі.
  • Описуйте збірку, а не власний комп'ютер. build працює на комп'ютері збирання. Домашня тека або змінна середовища, прочитана там, запікається для кожного гравця. Використовуйте змінні на зразок ${root} для шляхів.
  • Жодних секретів у тому, що повертаєте. Бандл це zip, який отримують інші люди.
  • Володейте своїми іменами. Починайте змінні з імені вашого плагіна, щоб вони не могли зіткнутися зі змінними іншого плагіна. Виберіть ім'я плагіна, яке добре читається у '@name.group'.
  • Приймайте один об'єкт параметрів, як вбудовані плагіни, щоб конфігурації читалися однаково всюди.

Можливо, він вам не потрібен ​

Перш ніж писати плагін, перевірте, чи наявний не робить цієї роботи:

  • Тека файлів: files.
  • Файл за URL: links.
  • Наявний плагін, що майже підходить: підправте його вивід через .exclude() і подібні. Кожен плагін, зроблений з definePlugin, має ці методи, включно з вашим.