« ^ »

MinetestのModを作る

所要時間: 約 4分

Minetestはマインクラフトのようなボクセルゲームであり、そのソースコードは自由ソフトウェアとして公開されている。Minetestの中核はC++で実装されているが、ModはLuaで実装されている。もし独自のModを実装しようと思ったなら、Luaに向き合う事になる。しかし実装方法やAPIのドキュメントは整備されていない。私が考える一番効率的な方法は、既に動作しているModのコードをコピーして、無駄な所を削ぎ落しまず簡単な動作をさせる。その後、他のModのコードを参考に継ぎ接ぎして、動作を確認しながら成長させていくことだ。本当に面倒だし、なんでこんな事をしないといけないのだろうと思う事もある。でも、きっとMinetestユーザーはModを作りたくなるだろう。そういうものだ。この面倒さを楽しむという事がMinetestという遊びなんだと思う。とはいってもヒントというものは多いに越した事はない。この文章が、その遊びのヒントになればと思う。

https://res.cloudinary.com/symdon/image/upload/v1676119627/blog.symdon.info/1675337483/qp1tfnrklkwyiaf0puwm.jpg

デプロイしたMinetestのサーバーにはゲームデータを保持するディレクトリとゲームを構成するディレクトリがある。ゲームデータを保持するディレクトリには、ゲームプレイヤーの情報やワールドを構成するブロックやジオメトリの情報などを記録したファイルが格納されている。一方ゲームを構成するディレクトリというのは、ゲーム自体の構成情報が格納されており、そこにModも格納されている。Minetestはゲームという単位で設定やModを入れ替えることで、ゲームの中身を大きく変更できる。私は minetest_game という物を使用しているから、ディレクトリは /opt/minetest/games/minetest_game となる。そして、Modは /opt/minetest/games/minetest_game/mods に格納されている。大まかなディレクトリの構成は次のようになる。

/opt/minetest
.
├── bin
├── builtin
├── games
│     └── minetest_game
│         ├── menu
│         ├── mods   <- Modを格納するディレクトリ
│         └── utils
└── worlds
    └── world3

mods ディレクトリに作成したModディレクトリを設置すると、Minetestは起動時にModを読み込む。Modのディレクトリ名はMod名と一致させる必要はない。だが同一にしておいた方が管理上はよいだろう。今回は例として symdon という名前のModを作成していくことにしよう。

Mod用のディレクトリを作成する。

mkdir -p symdon

Mod用のディレクトリにModのメタデータ用のファイルを作成する。

name = symdon
title = Symdon
description = Symdon Extention
author = TakesxiSximada
min_minetest_version = 5.0
license = LGPL
optional_depends = default

メタデータの各設定と意味をまとめた。

設定意味
nameMod名
titleModタイトル
descriptionModの説明
author作者
min_minetest_version対象となる最上のMinetestのバージョン
licenseライセンス
optional_dependsオプショナルの依存Mod
メタデータの設定と意味

nametitle にはどういう違いがあるのだろう。 title は表題であるのに対し、 name はModのシステム的に認識する名称というところだろうか。依存関係として指定する場合に使用するのは、おそらくこの name の方だろう。

他のModを見渡してみると、だいたい mod.conf と共に init.lua というファイルがある。ファイル名から初期化ファイルだと推測できる。今回は簡単なチャットコマンドを追加することにした。

symdon = {}

symdon.modname = minetest.get_current_modname()
symdon.modpath = minetest.get_modpath(symdon.modname)

minetest.register_chatcommand("symdon", {
     params = "",
     description = "Hello symdon",
     func = function (name, param)
       minetest.chat_send_player(name, "Hello, enjoy minetest.")
     end
})

このluaスクリプトでは minetest というオブジェクトにアクセスできる。このオブジェクトが一体何なのかは良くわからないが register_chatcommand を呼び出せるようだ。第1引数には追加するコマンドの文字列、第2引数には呼び出し可能なものを渡す。チャットコマンド実行時には、この第2引数に渡した処理が実行される。このコールバックには、呼び出したユーザーの名前と引数が渡される。

minetest.register_chatcommand("追加するコマンド名", {
     func = function (name, param)
       // name  :: チャットコマンドを入力したユーザー名が文字列として渡される
       // param :: コマンドの引数が渡される

       // 何かの処理を行う
     end
})

実行している minetest.chat_send_player()はユーザーに対してチャットメッセージを送信するメソッドだろう。第1引数には送信先のユーザー名、第2引数には送信するメッセージの文字列を指定する。

minetest.chat_send_player(name, "Hello, enjoy minetest.")

このModをディレクトリごとmods配下に配置する。

/opt/minetest
.
├── bin
├── builtin
├── games
│     └── minetest_game
│         ├── menu
│         ├── mods
│         │    └── symdon  <- ここにModのディレクトリを配置する
│         │          ├── mod.conf
│         │          └── init.lua
│         └── utils
└── worlds
    └── world3

サーバーを再起動すると /symdon というコマンドをゲーム内チャットとして使用できるようになる。