Minetestはマインクラフトのようなボクセルゲームであり、そのソースコードは自由ソフトウェアとして公開されている。Minetestの中核はC++で実装されているが、ModはLuaで実装されている。もし独自のModを実装しようと思ったなら、Luaに向き合う事になる。しかし実装方法やAPIのドキュメントは整備されていない。私が考える一番効率的な方法は、既に動作しているModのコードをコピーして、無駄な所を削ぎ落しまず簡単な動作をさせる。その後、他のModのコードを参考に継ぎ接ぎして、動作を確認しながら成長させていくことだ。本当に面倒だし、なんでこんな事をしないといけないのだろうと思う事もある。でも、きっとMinetestユーザーはModを作りたくなるだろう。そういうものだ。この面倒さを楽しむという事がMinetestという遊びなんだと思う。とはいってもヒントというものは多いに越した事はない。この文章が、その遊びのヒントになればと思う。
デプロイした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
メタデータの各設定と意味をまとめた。
設定 | 意味 |
---|---|
name | Mod名 |
title | Modタイトル |
description | Modの説明 |
author | 作者 |
min_minetest_version | 対象となる最上のMinetestのバージョン |
license | ライセンス |
optional_depends | オプショナルの依存Mod |
name
と title
にはどういう違いがあるのだろう。 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
というコマンドをゲーム内チャットとして使用できるようになる。