NeovimでScalaを使ってマインクラフトのプラグインを作ってみる
この記事はVim駅伝の2023-05-08向け記事です
tl;dr
- Metalsを使えばNeovimでもScalaは書ける
- マインクラフトのプラグインを作るならローカル環境を整備しよう
対象読者
- Neovimを良く使う
- VSCodeに未だ馴染めない
- Scalaで開発をする
- (Optional) マインクラフトのSpigotMC向けプラグインを作りたい
おことわり
正直、Scalaでの開発をするためにNeovimを使うのはオススメできません。
VSCodeやIntelliJを使う方が賢い選択だと思います。
Neovimに馴染んでいて、どうしてもNeovimでやりたい、という人だけが挑戦するべきことだと考えています。
NeovimでScalaを使ってマインクラフトのプラグインを作るまでの軌跡
- Scala開発環境を構築する
- Scalaプロジェクトのtemplateを用意する
- マインクラフトプラグインのtemplateを用意する
- 試しに動かしてみる
Scala開発環境を構築する
Neovimのユーザーの内いくらかは、LSP(Language Server Protocol)を前提にした言語サーバーを介して、
- 補完
- 診断(Diagnostics)の実行
- 定義ジャンプ
など、各種編集支援を受けているものと思います。
Scalaにも有志によって言語サーバーが用意されており、Metalsの名で公開されています。
公式オススメのMetals利用方法
Metals公式では、nvim-metalsを使う方法がオススメされています。
デバッガと連携する Dap
のサポートなど、様々なLSの枠を越えた機能が提供されていること、
フルセットでのセットアップが公式にメンテナンスされていることなどがメリットのようです。
作者自身が、「なぜnvim-lspconfigとの組み合わせではなく、nvim-metalsを使うべきか」と題してDiscussionに表明しています。
だが断る
私は「作者の方針に一度従ってみる」というのを大切にしているため、
一度は公式オススメのnvim-metalsを使った方法を利用してみました。
しかし、
- negative:
- telescope.nvimと徒に結合する
- statuslineを犯してこようとする
- 他の言語サーバーのattachとの共存が地味に面倒くさい
- keymapの設定を公式オススメからコピペすると他の言語サーバーと異なる設定になってしまう
- positive:
- 他の言語サーバーのための設定が流用できるため、殆どMetalsのための設定は必要ない
- Metalsの推しているLSPの枠を越えた機能利用に今のところ必要性を感じていない
など、小さなポリシーのずれを感じるシーンが多く、結局nvim-lspconfigとMetalsを自前で連携した方が楽、という結論に至りました。
実際、十分nvim-lspconfigが設定されている私の環境では、Metalsの為に必要な設定はごく僅かでした。
(nvim-metalsを取り除く差分含み)
- Metalsをインストールする
- nvim-lspconfigで
metals
のセットアップを呼び出す
だけで環境構築が完了しています。
LSP様々、といった感じですね。
nvim-metals独自の機能なども、恐らくLSPのAttachでちょっとした処理を追加するだけで済みそうです。
後々設定した際にはここに追記していこうと思います。
Scalaプロジェクトのtemplateを用意する
環境構築が終わったら、Scalaのプロジェクトを用意していきます。
といっても、公式マニュアルにある方法をそのまま実行するだけです。
SBT公式ドキュメントより:sbt new and Templates
- 適当なディレクトリで
sbt new scala/scala3.g8
を実行する- Template(例では
scala/scala3.g8
)にはいくつかの種類があるので、詳しくは上記マニュアル参照
- Template(例では
- プロジェクトの名前を問われるので、答える
だけのことです。これで以下のような基本ファイルが用意されます。
- <project name>/
- README.md
- build.sbt
- project/
- build.properties
- src/
- main/
- scala/
- Main.scala
- scala/
- test/
- scala/
- MySuite.scala
- scala/
- main/
- .gitignore
やや脱線する話ではありますが、このとき用意される.gitignore
にはなぜか
# macOS
.DS_Store
# VS Code
.vscode/
のように、開発者の環境に依存した内容が書かれています。
こういう開発者の環境に必要なignore条件は各開発者がgit config --global
で設定するべきものですから、取り除いておいてもいいかもしれません。
マインクラフトプラグインのtemplateを用意する
Scalaプロジェクトのtemplateが用意できたところで、次はマインクラフトのプラグインのtemplateを作っていきましょう。
こちらもSpigotMCの公式ドキュメントに従えばさほど難しくはありません。
- SpigotMCの開発に必要なライブラリを追加する
-
build.sbt
のlibraryDependencies
に"org.spigotmc" % "spigot-api" % "1.19.4-R0.1-SNAPSHOT"
を追加する - 同じく
resolvers
に"spigot-repo" at "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
を追加する - ref: https://github.com/thinca/MODal/pull/23/commits/a452dedcfedf6c5a360a9d60051dbdad4bc34813
-
- 既存の不要なMainクラスは削除しておく
- Pluginクラスを実際に置く
- Pluginクラスは
org.bukkit.plugin.java.JavaPlugin
を実装する - e.g.
class HogePlugin extends JavaPlugin:
- Pluginクラスは
- プラグインのprofileを設置する
-
main
には先に追加したクラスを示す - ref: https://github.com/thinca/MODal/pull/23/commits/366b38e2287d8301bf2a8cc1292381df9be17697
-
というだけのことです。
試しに動かしてみる
SpigotMCプラグイン開発の場合、テストを自動化するにしても実際に触ってみるにしても、
SpigotMCのサーバーを立ち上げて動かしてみた方が良いでしょう。
私が関わっているMODalというプラグインの場合、@thincaさんがDockerコンテナを用意してくれていました。
自身のマインクラフトのプレイヤーID(またはUUID)を環境変数に設定しておけば、
そのプレイヤーをOPSとした環境を、docker compose
を使ってコンテナを起動できます。
$ export MINECRAFT_OPS_PLAYER_ID=xxxxxxx
$ docker compose up -d
このコンテナでは、ホストの.local/data
を/data
にマウントしています。
そして/data/plugins
をプラグインディレクトリとして扱っています。
従って、ビルドした.jar
ファイルを.local/data/plugins/*.jar
に設置すれば、有効なプラグインとして利用できます。
$ sbt package
$ mkdir -p ./.local/data/plugins/
$ cp ./target/scala-3.2.2/hoge_0.1.0.jar ./.local/data/plugins/
プラグインを設置したら、コンテナを再起動してプラグインの更新を反映しましょう。
$ docker compose up -d --force-recreate
ところで、SpigotMCにはPlugManXというプラグインがあります。
これを利用すると、プラグインのホットリロードが実現でき、時間のかかるコンテナの再起動をせずにすみます。
外部からホットリロードをかける場合:
$ docker compose exec minecraft rcon-cli plugman reload MODal
マイクラ内のコマンドラインからホットリロードをかける場合:
/plugman reload MODal
こちらのプラグインについても@thincaさんから教えていただきました。
おわりに
かなりマニアックな試みでしたが、快適な開発環境を得られています。
他にもNeovimでScalaを使ってマインクラフトのプラグインを書いてみたい、という人が何かの間違いで存在し、参考にしていただければ幸いです。
多くのTips、助言をいただけた@thincaさんに感謝!
Discussion