플러그인

플러그인은 plugin.json 매니페스트 파일과 그 옆의 plugin.ts 또는 plugin.js로 이루어집니다. 플러그인 API로 에디터를 폭넓게 고치고 기능을 더할 수 있습니다. 에디터 안에서는 플러그인 ▸ 플러그인 찾아보기에서 볼 수 있습니다.

직접 만든 플러그인은 이 이슈 양식을 작성해 목록에 올릴 수 있습니다.

이 목록은 에디터의 플러그인 찾아보기가 읽는 것과 같은 색인(scm-js/registry)을 그대로 보여 주므로, 지금 에디터에서 받을 수 있는 플러그인과 항상 같습니다. 플러그인 설명은 색인에 적힌 영어 원문 그대로입니다.

레지스트리를 불러오는 중…

플러그인 만들기

API

플러그인은 파일 두 개입니다. 코드가 어디 있는지 적은 plugin.json과, activate(api)를 기본 내보내기로 하는 진입 파일입니다. 플러그인을 켜면 에디터가 이 함수를 한 번 호출하면서 api를 넘겨줍니다.

이것으로 열린 맵을 읽고 쓰고, 에디터 화면에 무언가를 더하고(메뉴와 컨텍스트 메뉴 항목, 단축키, 대화 상자, 떠 있는 패널, 포인터를 맡는 맵 도구, 캔버스 위에 그리는 오버레이), 게임의 .dat 테이블을 디코딩된 형태로 읽을 수 있습니다. 등록한 것은 플러그인을 끄면 모두 자동으로 치워집니다.

모든 쓰기는 api.document.edit(label, tx => …)를 거칩니다. 콜백이 한 일은 실행 취소 한 단계가 되고, 건드린 CHK 섹션이 표시되며, 화면이 다시 그려집니다. 그래서 플러그인의 편집도 다른 붓질처럼 실행 취소와 다시 실행에 들어갑니다.

API는 Promise를 기본으로 합니다. 비동기인 것은 모두 Promise를 돌려주고, activate와 대화 상자 버튼의 run은 async여도 되며, 사용자가 취소하면 거부 대신 null이나 false로 끝납니다. 단 하나의 예외는 edit에 넘기는 콜백입니다. 콜백이 돌아오는 순간 커밋되므로, async 콜백은 첫 await 전까지 한 일만 커밋하고 나머지는 실행 취소 단계 밖에서 쓰게 됩니다. 그래픽, 맵에서 고른 위치, 네트워크 요청은 먼저 기다린 다음 한 번에 쓰세요. TypeScript는 async 콜백을 아예 거부하고, 일반 JavaScript에서는 실행할 때 잡아냅니다.

export default function activate(api) {
  api.menu.add("Tools", {
    label: "Marine here…",
    enabled: () => api.document.isOpen(),
    async run() {
      // Asynchronous, so await it. Esc or a right-click resolves null.
      const at = await api.ui.pickTile({ prompt: "Where does the marine go?" });
      if (!at) return;

      // Synchronous, so the whole thing is one undo entry called "Place a marine".
      api.document.edit("Place a marine", (tx) => {
        const px = api.consts.TILE_PX;
        tx.placeUnit(0, 0, at.x * px + px / 2, at.y * px + px / 2);
      });
    },
  });
}

TypeScript는 브라우저에서 변환되므로, 파일 하나짜리 플러그인에는 도구가 전혀 필요 없습니다. npm 의존성이 필요한 저장소는 번들을 커밋하고 매니페스트에 그 이름을 적습니다.

목록에 오르려면

scm-js 조직에 있는 plugin-… 이름의 저장소나, scmjs와 plugin 토픽이 달린 저장소는 레지스트리 생성기가 가장 최근의 semver 태그로 가져갑니다. 그 밖의 플러그인은 에디터에 주소를 붙여 넣어 설치할 수 있습니다.